数据结构课程设计--图的遍历
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构课程设计--图的遍历
内蒙古科技大学
本科生课程设计论文
题目:图的遍历
2013年07月05日
内蒙古科技大学课程设计任务书
目录
第一章图的遍历原理5
1.1总述6
1.2深度优先遍历6
1.3广度优先遍历
6
第二章需求分析7
第三章总体设计 (7)
3.1程序设计思路 (7)
3.2 功能视图 (8)
第四章类的设计 (8)
4.1 GraphUDN类的设计 (9)
4.2 Queue类的设计 (10)
第五章详细设计 (10)
5.1 工程视图和类视图 (10)
5.2 主要算法的流程图 (11)
5.2.1 主函数的流程图 (11)
5.2.2 深搜流程图 (12)
5.2.3 广搜流程图 (13)
第六章测试 (14)
6.1 菜单界面 (15)
6.2 创建无向网 (15)
6.3 输出图 (16)
6.4 输出顶点V的第一个邻接点 (16)
6.5 输出顶点V的下一个邻接点 (17)
6.6 深搜 (17)
6.7 广搜 (18)
第七章总结 (18)
附录:程序代码 (20)
参考文献 (29)
第一章图的遍历原理
1.1总述
图的遍历:从图中某一顶点出发访遍图中其余顶点,且使得每一个顶点仅被访问一次。
这一过程就叫做图的遍历。
1.2深度优先遍历
深度优先遍历类似于树的先根遍历,是树的先根遍历的推广。
假如初始状态是图中所有顶点未曾被访问,则深度优先遍历可从图中某个顶点V出发,访问此顶点,然后依次从V的未被访问的邻接点出发深度优先遍历图,直到图中所有和V有路径相通的顶点都被访问到;若图中此时尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直到图中所有顶点都被访问到为止。
以图1.1为例,假如从顶点V1出发进行搜索,在访问了顶点V1之后,选择邻接点V2。
因为V2未曾访问,则从V2出发进行搜索。
以此类推,接着从V4,V8,V5出发进行搜索。
在访问了V5之后,由于V5的邻接点都已被访问,则搜索回到V8。
由于同样的理由,搜索回到V4,V2直到V1,此时由于V1的另一个邻接点未被访问,则搜索又从V1到V3,再继续进行下去。
由此,得到的顶点访问序列为:
V1—V2—V4—V8—V5—V3—V6—V7
1.3广度优先遍历
广度优先遍历类似于树的按层次遍历的过程。
假如从图中某顶点V出发,在访问了V之后依次访问V的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直到图中所有已被访问的顶点的邻接点都被访问到。
若图中此时尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直到图中所有顶点都被访问到为止。
以图1.1为例,首先访问V1和V1的邻接点V2和V3,然后依次访问V2的邻接点V4和V5及V3的邻接点V6和V7,最后访问V4的邻接点V8。
由于这些顶点的邻接点均已被访问,并且图中所有顶点都被访问,由此完成图的遍历。
得到的顶点访问序列为:
V1—V2—V3—V4—V5—V6—V7—V8
第二章需求分析
要求设计类(或类模板)来描述图,包含必要的构造函数和析构函数,以及其他能够完成如下功能的成员函数:
❖输入图、输出图
❖求图中顶点V的第一个邻接点
❖求图中顶点V的下一个邻接点
❖深度优先遍历图
❖广度优先遍历图
并设计主函数测试该类(或类模板)。
第三章总体设计
3.1程序设计思路
本系统有六个基本功能:输入图,输出图,求图中顶点V的第一个邻接点,求图中顶点V的下一个邻接点,深度优先遍历图,广度优先遍历图。
输入图:首先需输入顶点数及边数,然后根据顶点数确定矩阵大小,再根据边数输入对应的两点及权值。
输出图:先输出有所有边及对应的权值,再输出矩阵。
求图中顶点V的第一个邻接点:通过输入顶点v就可以输出其第一个邻接点。
求图中顶点V的下一个邻接点:通过输入顶点v及另一点,就可以从该位置的下一个位置开始,找到顶点V的下一个邻接点。
深度优先遍历图:由1.1所述可知,图的深度优先遍历显然是一个递归的过程。
为了在遍历过程中便于区分顶点是否被访问过,需要附设一个访问标志数组,其初始值为false,一旦某个顶点被访问,则将其相应的分量置为true。
广度优先遍历图:由1.2所述可知,和深度优先遍历类似,在广度优先遍历的过程中也需要一个访问标志数组。
并且为了顺次访问路径长度为2,3,……的顶点,需要附设队列以存储已被访问的路径长度为1,2,……的顶点。
3.2 功能视图
本程序主要包含六个功能,即图的创建,输出,访问顶点V的第一个和下一个邻接点,以及深搜和广搜。
其功能视图如图2.1所示。
无向图的实
现
创建无向图输出无向图访问邻接顶
点
访问下一个
邻接顶点
深度优先遍
历
广度优先遍
历图3.1功能视图
第四章类的设计
4.1 GraphUDN类的设计
GraphUDN类包括:1.私有的数据成员,其中有顶点访问标志,顶点集,邻接矩阵,顶点数就边数 2.公有的成员函数,其中有创建输出图,输出顶点V的第一个和下一个邻接点,以及深搜和广搜。
具体见以下程序段:classGraphUDN {
public:
GraphUDN ();
void create(); //创建图
void showGraph(); //输出图
intfirstAdjvex(int v); //输出v的第一个邻接顶点
intnextAdjvex(int v, int w); //输出下一个邻接顶点
void dfsTravel(); //深度优先遍历
voiddfs(int v);
void bfsTravel(); //广度优先遍历
private:
bool visited[MAX_VERTEX_NUM]; //顶点访问标志
int vexs[MAX_VERTEX_NUM]; //顶点集
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
intvexNum;
intarcNum;
};
4.2 Queue类的设计
Queue类作为一个辅助的功能类,主要包括入队,出队及队列的判空。
具体如下:
class Queue {
public:
Queue (){
for(inti = 0; i< MAX_VERTEX_NUM; i++){
ques[i] = -1;
}
};
void add(intele); //入队
int get(); //出队
boolisEmpty(); //判断队列是否为空
private:
intques[MAX_VERTEX_NUM];
};
第五章详细设计
5.1 工程视图和类视图
本程序运行时的工程视图及类视图如图5.1,5.2所示。
图5.1 工程视图
图5.2 类视图
5.2主要算法的流程图
5.2.1 主函数的流程图
本程序的主函数中,首先定义及初始化所需变量,实例化对象,然后输出菜单界面供用户选择,通过switch函数实现选择功能,选择项目包括创建无向图,
输出无向图,输出顶点V的第一个邻接点,输出顶点V的下一个邻接点,深搜,广搜以及退出。
具体如图4.3所示。
图 5.3主函数流程图
5.2.2 深搜流程图
深度优先遍历图的过程实质上是对每个顶点查找其邻接点的过程,具体
如图5.4所示:
图 5.4深度优先算法遍历流程图
5.2.3 广搜流程图
广度优先遍历的过程实质上就是通过边找邻接点的过程,具体如图 5.5所示:
图 5.5广度优先算法遍历流程图第六章测试
6.1 菜单界面
当运行程序后,首先出现菜单界面,包括程序提供的六个功能,用户通过选择功能前的数字,即可实现相应的功能。
具体如图6.1所示。
图6.1 菜单界面
6.2 创建无向网
接下来应当创建一个图,通过输入顶点数,边数,邻接点及权值即可实现。
在本次测试中,建立的是一个8个顶点,9条边的且所有边的权值均为1的无向网。
输入如图6.2所示
图6.2 创建图
6.3 输出图
当输入图以后,实际图是以邻接矩阵的形式存在的,所以输出图的时候输出的就是邻接矩阵,为方便理解,还输出了邻接点及对应边的权值。
输出结果如图6.3所示。
图6.3 输出图
6.4 输出顶点V的第一个邻接点
实际上输出顶点V的第一个邻接点并无太大的意义,因为这个函数主要是为了实现深搜和广搜功能而编写的,但在此处,为了更加便于普通用户理解此程序,特意添加了此操作,具体操作及结果如图6.4所示。
图6.4 输出V的第一个邻接点
6.5 输出顶点V的下一个邻接点
如同6.4节所述,输出顶点V的下一个邻接点也并无太大意义,同样是为了便于普通用户理解,具体操作及结果如图6.5所示。
图6.5 输出V的下一个邻接点
6.6 深搜
深度优先遍历图相当于树的先序遍历,具体原理见所述,针对本次测试所创建的图,它的深度优先遍历结果如图6.6所示。
图6.6 深度优先搜索
6.7 广搜
广度优先遍历图相当于树的层次遍历,具体原理见所述,针对本次测试所创建的图,它的广度优先遍历结果如图6.7所示。
图6.7 广度优先搜索
第七章总结
转眼之间,为期两周的课程设计就结束了,通过这两个星期的课程设计,我发现了自己很多不足的地方,知识点也存在很多漏洞,还接触了一些以前没有了解的东西,让我明白了基础知识的重要性,以及实践能力的重要性!因为基础知识的不扎实让我在这次课程设计中走了许多弯路,不过我认为是值得的,
至少它让我明白了,付出与回报是成正比的。
这次的课程设计,可以说是有苦有甜。
苦的是,由于学习数据结构课程的时候,并没有过多的涉及文件操作的知识,所以到课程设计的时候,我不得不通过看书,问同学老师以及上网查询来了解关于文件操作的知识点。
甜的是,在程序设计过程中,不仅检验、巩固了我以前所学的知识,也让我如何去把握一件事情,如何去做一件事情,又如何完成一件事情,当看到自己亲自设计,调试好的程序运行的时候,心里有一种说不出的自豪感和成就感。
“千里之行始于足下”,通过这次课程设计,我深深体会到这句千古名言的真正含义。
课程设计是培养我们综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对我们实际工作能力的具体训练和考察过程。
它为我们提供了一个既动手又动脑,独立实践的机会,将课本上的理论知识和实际有机的结合起来,锻炼我们的分析解决实际问题的能力。
提高我们运用所学知识解决实际问题的能力。
课程设计这类实践训练是我们迈向社会,从事职业工作前一个必不少的过程。
所以通过这次的课程设计,也让我对自己的职业工作有了进一步的了解。
通过这次图的遍历的设计,我在多方面都有所提高。
首先,整体与局部的把握,在系统设计前,需要整体思考图的遍历所包含的信息及其实现的功能,在设计过程中,再思考局部功能实现的完整性与整个程序的结合。
其次,在实现信息储存这个功能时,通过查阅课本、资料,实践,对文件操作有了更深的了解,能够熟练运用I/O流,而且加强了对类中函数成员使用等知识,并通过条件以及循环语句实现不同的操作。
课程设计使我对数据结构课程又进行了系统的复习,独立思考的能力也有了提高。
在程序设计运行过程中遇到错误,就通过与同学讨论、研究,集思广益,更改代码,不断的尝试实践运行各种方法……虽然在这个过程中遇到了很多问题,但程序编辑成功后那种激动,使我深深地体会到了学习的快乐和团结的力量,也让我真正学习到了一些的知识,使我感到未来是充满挑战与趣味的。
通过这次编程使我认识到在以后的学习中要多做练习增加自己的知识面才能更好的适应自己的工作,不管遇到什么,都要充满信心地去解决问题。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知
识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。
而且这次课程设计也让我受益匪浅,真切感觉到任何事情都需要细心和耐心,二者缺一不可。
没有细心,做事情永远都是事倍功半,一旦某个细节错了,就会导致某个部分应用不了额,甚至可能导致整个系统都运行不了。
没了耐心,可能就会导致这件事不能够完成,经常半途而废。
当然,任何一件事的顺利完成都不是靠一个人就可以的,在此感谢丁雨老师对我细心的指导,同时也非常感谢给予我帮助的同学们,谢谢你们。
总而言之,这次课程设计不仅让我学到了关于数据结构的更多的知识,也让我明白了要完成一件事情所需要的精神。
附录:程序代码
#include <iostream.h>
#define MAX_VERTEX_NUM 20
//-------------------队列----------------------------
class Queue {
public:
Queue (){
for(int i = 0; i < MAX_VERTEX_NUM; i++){ ques[i] = -1;
}
};
void add(int ele); //入队
int get(); //出队
bool isEmpty(); //判断队列是否为空private:
int ques[MAX_VERTEX_NUM];
};
void Queue::add(int ele){
for(int i = 0; i < MAX_VERTEX_NUM; i++){ if(ques[i] == -1){
ques[i] = ele;
break;
}
}
}
int Queue::get(){
int ele = ques[0];
for(int i = 0; i < MAX_VERTEX_NUM; i++){ int t;
t = ques[i];
ques[i] = ques[i + 1];
ques[i + 1] = t;
}
return ele;
}
bool Queue::isEmpty(){
if(ques[0] != -1){
return false;
}else{
return true;
}
}
//---------------队列类结束--------------------
//输出顶点
void visite(int vl){
vl = vl + 1;
cout<<vl<<"->";
return;
}
//--------------无向网类----------------------
class GraphUDN {
public:
GraphUDN ();
void create(); //创建图
void showGraph(); //输出图
int firstAdjvex(int v); //输出v的第一个邻接顶点 int nextAdjvex(int v, int w); //输出下一个邻接顶点
void dfsTravel(); //深度优先遍历
void dfs(int v);
void bfsTravel(); //广度优先遍历
private:
bool visited[MAX_VERTEX_NUM]; //顶点访问标志
int vexs[MAX_VERTEX_NUM]; //顶点集
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
int vexNum;
int arcNum;
};
GraphUDN::GraphUDN(){
}
void GraphUDN::create(){
cout<<"请输入顶点数,以及边数"<<endl;
cin>>vexNum>>arcNum;
//构造顶点向量
for (int p = 0; p < vexNum; p++) {
visited[p] = false;
vexs[p] = p + 1;
}
//初始化邻接矩阵
for (int i = 0; i < vexNum; i++) {
for (int j = 0; j < vexNum; j++) {
arcs[i][j] = 0;
}
}
//构造邻接矩阵
int v1,v2,w;
for (int k = 0; k < arcNum; k++) {
cout<<"请输入邻接矩阵,v1,v2,w:";
cin>>v1>>v2>>w;
int i,j;
i = v1-1;
j = v2-1;
arcs[i][j] = w;
arcs[j][i] = arcs[i][j];
}
}
void GraphUDN::showGraph(){
for (int i = 0; i < vexNum; i++) {
for (int j = i; j < vexNum; j++) {
if (arcs[i][j] != 0) {
cout<<vexs[i]<<" -("<<arcs[i][j]<<")-> "<<vexs[j]<<" "<<endl;
}
}
}
cout<<"邻接矩阵:"<<endl;
for (int k = 0; k < vexNum; k++) {
for (int p = 0; p < vexNum; p++) {
cout<<arcs[k][p]<<" ";
}
cout<<endl;
}
}
int GraphUDN::firstAdjvex(int v){
for(int i = 0; i < vexNum; i++){
if(arcs[v][i] != 0){
return i;
}
}
return -1;
}
int GraphUDN::nextAdjvex(int v, int w){
for(int i = w+1; i < vexNum; i++) {
if(arcs[v][i]!=0 && visited[i]==false){
return i;
}
}
return -1;
}
void GraphUDN::dfsTravel(){
int i;
for(i=0; i < vexNum; i++)
visited[i] = false;
for(i=0; i < vexNum; i++) //从0开始
if(visited[i] == false)
dfs(i);
cout<<"结束"<<endl;
}
void GraphUDN::dfs(int v){
int w;
visited[v] = true;
visite(v);
for(w = firstAdjvex(v); w != -1; w = nextAdjvex(v,w)){
if(visited[w]==false)
dfs(w);
}
}
void GraphUDN::bfsTravel(){
for (int i = 0; i < vexNum; i++){
visited[i] = false;
}
Queue que;
for (i = 0; i < vexNum; i++){
if (visited[i] == false){
visited[i] = true;
visite(i);
que.add(i);
while (!que.isEmpty()){
int u = que.get();
for (int w = firstAdjvex(u); w>=0; w=nextAdjvex(u, w)){ if (visited[w] == false){
visited[w] = true;
visite(w);
que.add(w);
}
}
}
}
}
cout<<"结束"<<endl;
}
//----------------------------------------------------------------
//主函数
void main(){
bool flat = true;
int select;
int vex,w,result;
GraphUDN grap;
while (flat){
cout<<"---------------------------------------"<<endl;
cout<<" 1、创建无向图;"<<endl;
cout<<" 2、输出无向图;"<<endl;
cout<<" 3、输出顶点v的第一个邻接顶点;"<<endl;
cout<<" 4、输出顶点v的下一个邻接顶点;"<<endl;
cout<<" 5、深度优先遍历图;"<<endl;
cout<<" 6、广度优先遍历图;"<<endl;
cout<<" 7、退出。
"<<endl;
cout<<" 请输入操作:"<<endl;
cout<<"---------------------------------------"<<endl;
cin>>select;
switch (select){
case 1:
grap.create();
break;
case 2:
grap.showGraph();
break;
case 3:
cout<<"请输入顶点:";
cin>>vex;
cout<<"v的第一个邻接顶点:"<<grap.firstAdjvex(vex-1) + 1<<endl;
break;
case 4:
cout<<"请输入顶点以及邻接顶点:";
cin>>vex>>w;
result = grap.nextAdjvex(vex-1, w-1);
if ( result < 0){
cout<<"v无下一个邻接顶点!"<<endl;
}else{
cout<<"v的下一个邻接顶点:"<<result + 1<<endl;
}
break;
case 5:
grap.dfsTravel();
break;
case 6:
grap.bfsTravel();
break;
case 7:
flat = false;
break;
default:
cout<<"请重新输入"<<endl;
内蒙古科技大学课程设计论文
}
}
}
参考文献
[1] 严蔚敏吴伟民编著.数据结构(C语言版).北京:清华大学出版社
[2] 杨国林吴敏主编.C++面向对象程序设计.内蒙古.内蒙古大学出版社
[3] 李建学编著数据结构课程设计案例精编(用C/C++描述).清华大学出版
社 2007.2
[4] 殷人昆主编数据结构:用面向对象方法与C++语言描述. 清华大学出版
社 2007.6
29。