算法与数据结构的课设.docx
《算法与数据结构的课设.docx》由会员分享,可在线阅读,更多相关《算法与数据结构的课设.docx(34页珍藏版)》请在冰豆网上搜索。
算法与数据结构的课设
数据结构课程设计报告
系(院):
计算机科学学院
专业班级:
计科10904班
姓名:
陈天榜
学号:
200903735
指导教师:
周云才
设计时间:
2011.6.13-2011.6.25
设计地点:
4#2号机房
目录
一、课程设计目的1
二.设计任务及要求1
三、总体设计2
四、需求分析、详细设计与实现3
五、课程设计小结27
一、课程设计目的
1.能根据实际问题的具体情况,结合数据结构课程中的基本理论和基本算法,分析并正确确定数据的逻辑结构,合理地选择相应的存储结构,并能设计出解决问题的有效算法。
2.提高程序设计和调试能力。
学生通过上机实习,验证自己设计的算法的正确性。
学会有效利用基本调试方法,迅速找出程序代码中的错误并且修改。
3.初步掌握软件开发过程中问题分析、系统设计、程序编码、测试等基本方法和技能。
4.训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。
5.培养根据选题需要选择学习书籍,查阅文献资料的自学能力。
二.设计任务及要求
设计一个基于DOS菜单的应用程序。
要利用多级菜单实现各种功能。
内容如下:
1.无向图的基本操作及应用
1创建无向图的邻接矩阵
2创建无向图的邻接表
3无向图的深度优先遍历
4无向图的广度优先遍历
2.无向网的基本操作及应用
1创建无向网的邻接矩阵
2创建无向网的邻接表
3求最小生成树
3.有向图的基本操作及应用
1创建有向图的邻接矩阵
2创建有向图的邻接表
3拓扑排序
4.有向网的基本操作及应用
1创建有向网的邻接矩阵
2创建有向网的邻接表
3关键路径
4单源最短路径
5每对顶点之间的最短路径
设计要求
程序实现
a)完成基本结构图,程序中有三级菜单,完成基本操作者及格;
b)在第一条的基础上,任务完成的越多,成绩等级越高。
c)使用面向对象实现的可以适当加分。
三、总体设计
根据设计任务,设计一个DOS菜单,通过voidShowMainMenu()函数设计一个主菜单;再分别用函数实现菜单中的各项要求,由于菜单中每项要求包含多个操作,我们在函数中用switch选择语句选择调用每项操作函数;最后再通过Main函数调用以及switch选择语句调用主菜单和主菜单中各项要求的函数来完成各项要求的基本操作;
四、需求分析、详细设计与实现
1、创建无向图邻接矩阵
邻接矩阵结构体的定义如下:
typedefstructArcCell
{
intadj;
int*info;
}ArcCell,AdjMatrix[MaxSize][MaxSize];
typedefstruct
{
charvexs[MaxSize];
AdjMatrixarcs;
intvexnum,arcnum;
GraphKindkind;
intvisited[MaxSize];
}MGraph;
其实质是创建一个二维数组,用来存放两个顶点之间的关系,具体是通过它的adj属性,表示顶点的关系类型,这里的G.arcs[i][j].adj=1;
由于图的邻接矩阵是对称的,所以G.arcs[j][i]=G.arcs[i][j];i,j的位置是同过Locate函数来确定的,函数定义如下:
intLocateVertex1(MGraph&G,charv)
{
inti;
for(i=0;iif(v==G.vexs[i])
returni;
return-1;
}(后面的求邻接矩阵函数中也有定位置的都通过该函数确定)
创建代码如下:
intCreateUDG_AM(MGraph&G)
{
ifstreamfile1;
inti,j;
charv1,v2;
file1.open("E:
\\无向图.txt")
file1>>G.vexnum;file1>>G.arcnum;
for(i=0;ifile1>>G.vexs[i];
for(i=0;ifor(j=0;jG.arcs[i][j].adj=0;
for(intk=0;k{
file1>>v1>>v2;
i=LocateVertex1(G,v1);j=LocateVertex1(G,v2);
G.arcs[i][j].adj=1;
G.arcs[j][i]=G.arcs[i][j];
}
cout<<"无向图的邻接矩阵为:
"<for(i=0;i{
for(j=0;jcout<cout<}
return1;
}
这里我们是通过读文件的方法来实现其读取功能的,其输出结果入下图:
无向图文件均为此图;
2、创建无向图邻接表
邻接表中,对图中的么个顶点建立一个单链表,第i个单链表中的结点表示依附顶点vi的边。
每个结点由3个域组成,其中邻接点域(adjvex)指示与顶点vi邻接的点在图中的位置,链域nextarc指示下一条边的结点;数据域info储存和边得相关的信息。
每个链表上附设一个表头结点。
在表头结点中,除了设有链域指向链表中第一个结点之外,还设有存储顶点vi的名或其他有关信息的数据域data;代码如下:
typedefstructArcNode
{
intadjvex;
structArcNode*nextarc;
int*info;
intw;
}ArcNode;
typedefstructVNode
{
chardata;
ArcNode*firstarc;
}VNode,AdjList[MaxSize];
typedefstruct
{
intvexnum,arcnum;
AdjListvertices;
GraphKindkind;
}ALGraph;
intLocateVertex2(ALGraph&G,charv)
{
inti;
for(i=0;v!
=G.vertices[i].data&&iif(i>=G.vexnum)
return-1;
returni;
}
voidCreateUDG_AL(ALGraph&G)
{
ifstreamfile2;
charv1,v2;
file2.open("E:
\\无向图.txt");
file2>>G.vexnum;
file2>>G.arcnum;
for(inti=0;i{
file2>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
for(intk=0;k{
file2>>v1>>v2;
inti=LocateVertex2(G,v1);
intj=LocateVertex2(G,v2);Ì?
s=(ArcNode*)malloc(sizeof(ArcNode));
t=(ArcNode*)malloc(sizeof(ArcNode));
s->adjvex=j;
s->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=s;
t->adjvex=i;/
t->nextarc=G.vertices[j].firstarc;
G.vertices[j].firstarc=t;
}
}
这里的Locate函数是确定邻接表中的元素的位置;指针*t,*s分别指向其所指向的顶点的位置;输出代码如下:
voidDisPlayUDG(ALGraphG)
{
inti;
ArcNode*p;
cout<<"序号顶点相邻顶点编号"<for(i=0;i{
cout<<""<";
for(p=G.vertices[i].firstarc;p;p=p->nextarc)
cout<adjvex<<"->";
cout<<"^";
cout<}输出结构入下图:
3、无向图的深度优先遍历
深度优先搜索遍历,顾名思义就是从图中的某个顶点出发,访问此顶点,然后依次从该顶点的邻接点出发再次进行深度优先搜索遍历,直至图中所有和该顶点有路径相通的顶点都被访问到,若还有顶点没有访问到,则选择其中一个没有访问的顶点作为出发点进行遍历。
在遍历过程中要判断该顶点是否被访问需要一个intvisited[MaxSize];代码如下:
voidDFS(ALGraphG,intv)
{
intw;
visited[v]=1;
visit(G.vertices[v].data);
for(w=FirstAdjVertex(G,G.vertices[v].data);w>=0;w=NextAdjVertex(G,G.vertices[v].data,G.vertices[w].data))
{
if(!
visited[w])
DFS(G,w);
}
}
voidDFSTraverse(ALGraphG)
{
intv;
for(v=0;vvisited[v]=0;
for(v=0;v{
if(!
visited[v])
DFS(G,v);
}
}
当地一个顶点被访问后,就标记为访问。
然后访问其相邻的顶点,用一个for循环语句依次可以访问未被访问的顶点;结果如下:
4、无向图的广度优先遍历
广度优先搜索遍历类似于树的按层次遍历的过程。
过程是:
从图中某个顶点出发,在访问了该顶点之后依次访问该顶点的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,直至图中所有已被访问的顶点的邻接点都被访问到。
voidBFSTraverse(ALGraphG)
{
inti,v;
intfront,rear;
intqueue[MaxSize];
ArcNode*p;
front=rear=-1;
for(i=0;i{
visited[i]=0;/
}
v=0;
visited[v]=1;
visit(G.vertices[v].data);
rear=(1+rear)%MaxSize;
queue[rear]=v;
while(front{
front=(1+front)%MaxSize;
v=queue[front];
p=G.vertices[v].firstarc;
while(p!
=NULL)
{
if(visited[p->adjvex]==0)
{
visited[p->adjvex]=1;
visit(G.vertices[p->adjvex].data);/
rear=(1+rear)%MaxSize;
queue[rear]=p->adjvex;
}
p=p->nextarc;
}
}
这里主要运用到了队列的算法,因为队列的插入之限制于队尾,删除之限制于对头,刚好用于每个已经访问过的顶点以及未被访问的顶点;输出结果如下图:
5、邻接矩阵创建无向网
无向网的邻接矩阵对于无向网的邻接矩阵来说只是边上多了权值而已,操作类似于无向图;,对应的G.arcs[i][j].adj=w(权值);代码如下:
intCreateUDN_AM(MGraph&G)
{
ifstreamfile3;
inti,j,w;
charv1,v2;
file3.open("E:
\\无向网.txt");
file3>>G.vexnum;
file3>>G.arcnum;
for(i=0;ifile3>>G.vexs[i];
for(i=0;ifor(j=0;jG.arcs[i][j].adj=0;
for(intk=0;k{
file3>>v1;
file3>>v2;
file3>>w;
i=LocateVertex1(G,v1);
j=LocateVertex1(G,v2);
G.arcs[i][j].adj=w;
G.arcs[j][i]=G.arcs[i][j];
}
cout<<"无向网的邻接矩阵为:
"<for(i=0;i{
for(j=0;jcout<cout<}
return1;
}
无向网文件均为此图;
输出结果如下图:
6、邻接表创建无向网
无向网的邻接表跟无向图的邻接表类似,只需输入对应边的权值就可以了,代码如下:
voidCreateUDN_AL(ALGraph&G)
{
ArcNode*s,*t;
charv1,v2;
intw;
ifstreamfile6;
file6.open("E:
\\无向网.txt");
file6>>G.vexnum;
file6>>G.arcnum;
for(inti=0;i{
file6>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
for(intk=0;k{
file6>>v1>>v2>>w;
inti=LocateVertex2(G,v1);
intj=LocateVertex2(G,v2);
s=(ArcNode*)malloc(sizeof(ArcNode));
t=(ArcNode*)malloc(sizeof(ArcNode));
s->adjvex=j;
s->w=w;
s->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=s;
t->adjvex=i;
t->w=w;
t->nextarc=G.vertices[j].firstarc;
G.vertices[j].firstarc=t;
}
}
输出结果如下:
7、Prim算法求最小生成树
这里Prim算法针对的是无向网的邻接矩阵,在求算法是应先将邻接矩阵初始化,再创建邻接矩阵求最小生成树;Prim算法代码如下:
typedefstruct
{
charadjvex;
intlowcost;
}closedge[MaxSize];
intMinNum(MGraphG,closedgeedge)
{
inti=0,j,k;
intmin=INFINITY;
while(edge[i].lowcost==0)
i++;
min=edge[i].lowcost;
k=i;
for(j=i+1;j{
if(edge[j].lowcost>0&&edge[j].lowcost{
min=edge[j].lowcost;
k=j;
}
}
returnk;
}
voidPrim(MGraph&G,charv)
{
inti,j,k;
closedgeclosedge;
k=LocateVertex1(G,v);
for(j=0;j{
closedge[j].adjvex=v;
closedge[j].lowcost=G.arcs[k][j].adj;
}
closedge[k].lowcost=0;
cout<<"prim求得的最小生成树:
"<for(i=1;i{
k=MinNum(G,closedge);cout<<"("<closedge[k].lowcost=0;
for(j=0;jif(G.arcs[k][j].adj{
closedge[j].lowcost=G.arcs[k][j].adj;
closedge[j].adjvex=G.vexs[k];
}
}
}
}
先通过MinNum函数找出权值最小的边并返回其序号,再通过一个辅助数组closedge存储其权值;剩下的剩下按此方法找出再返回序号就可以求得一个最小生成树;结果如下:
8、Kruskal算法求最小生成树。
开始时每一个顶点都是一个连通分量,首先选择权值最小的边,并且两顶点在不同的连通分量上。
然后继续找权值最小的边,并且两个顶点在不同的连通分量上,当所有顶点在一个连通分量上时,得到的是最小上生成树!
代码如下:
voidKruskal(MGraphG,charu)
{
intset[MaxSize];
inti,j;
inta=0,b=0,k=0;
intmin=INFINITY;
for(i=0;i{
set[i]=i;
}
cout<<"kruskal算?
法¤¡§求¨®得Ì?
的Ì?
最Á?
小?
生¦¨²成¨¦树º¡Â:
êo"<while(k{
for(i=0;ifor(j=i+1;j{
if(G.arcs[i][j].adj{
min=G.arcs[i][j].adj;
a=i;
b=j;
}
}
min=G.arcs[a][b].adj=INFINITY;
if(set[a]!
=set[b])
{
cout<<"("<k++;
for(i=0;i{
if(set[i]==set[b]&&i!
=b)
{
set[i]=set[a];
}
}
set[b]=set[a];
}
min=G.arcs[a][b].adj=INFINITY;
}
}
其中set[]是辅助数组初始时set[i]=i表明每一个顶点代表一个连通分量。
当找到权值最小的边时并且两顶点在不同的连通分量上时输出:
cout<<"("<输入结果如下图:
9、邻接表创建有向图
有向图的邻接表跟无向图的差不多,只不过有向图中有方向性,所以创建的邻接矩阵并不是对称的;
有向图文件均为此图。
代码如下;
intCreateDG_AM(MGraph&G){
ifstreamfile5;
file5.open("E:
\\有®D向¨°图ª?
.txt");
inti,j;
charv1,v2;
file5>>G.vexnum;
file5>>G.arcnum;
for(i=0;ifile5>>G.vexs[i];
for(i=0;ifor(j=0;jG.arcs[i][j].adj=0;
for(intk=0;kfile5>>v1;
file5>>v2;
i=LocateVertex1(G,v1);
j=LocateVertex1(G,v2);
G.arcs[i][j].adj=1;
G.arcs[j][i].adj=0;
}
cout<<"有向图的邻接矩阵:
"<for(i=0;i{
for(j=0;jcout<cout<}
return1;
}
其中G.arcs[i][j].adj=1;G.arcs[j][i].adj=0;1表示i,j相邻。
0表示i,j不相邻;输出结果如下:
10、邻接表创建有向图
其创建方法与无向图的类似,代码如下:
voidCreateDG_AL(ALGraph&G){
ifstreamfile6;
file6.open("