数据结构课设图的基本应用和操作文档格式.docx
《数据结构课设图的基本应用和操作文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构课设图的基本应用和操作文档格式.docx(48页珍藏版)》请在冰豆网上搜索。
从图中的某个顶点出发,访问此顶点,然后依次从该顶点出发深度优先遍历图,直至图中所有与该顶点的有关路径都被访问到。
广度优先搜索遍历类似与数的按层次遍历的过程。
以某个顶点为起始顶点,由近至远,依次访问和该顶点有路径相同的额且路径长度为1,2,3….的顶点。
当图中所有顶点都被访问到后,就完成n个了图的广度优先搜索遍历。
求无向网的最小生成树问题有两种算法:
Prima和Kruskal算法。
Prima算法:
假设N=(V,E)是一个具有n个顶点的连通网,T=(U,TE)是所求的最小生成树,其中U是T的顶点集,TE是T的边集。
算法从U={u0}(u0∈V),TE={}开始
重复执行以下操作:
在所有u∈V,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直到U=V为止。
此时TE中必有n-1条边,则T为N的最小生成树。
Kruskal算法:
假设N=(V,E)是一个具有n个顶点的连通网,首先令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{})图中每个顶点自成一个连通分量。
然后在E中选择代价最小的边,若该边依附的两个顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。
依此类推,直到T中所有顶点都在同一连通分量上为止。
拓扑排序:
在有向图中,若用顶点表示活动,弧表示活动之间的先后关系,这种有向图称为顶点表示活动的网简称AOV网。
在AOV网中,若从顶点vi到顶点vj有一条有向路径,则vi是vj的前驱,vj是vi的后继。
若<
vi,vj>
是网中的一条弧,则vi是vj的直接前驱,vj是vi的直接后继。
如果vi是vj的前驱或直接前驱,则活动vi必须在vj开始之前结束,活动vj必须在活动vi结束之后才能开始。
如果不包含有向回路,则将全部活动排成一个线性序列,使得若活动Vi是活动Vj的前驱,则序列中Vi应该在Vj的前面。
具有这种特性的线性序列称为拓扑有序序列。
构造拓扑有序序列的过程称为拓扑排序。
关键路径:
在有向网中,用顶点表示事件,用弧表示活动,用弧上权值表示活动持续时间的网称为以边表示活动的网,简称AOE网。
几个相关的量:
设活动ai(k=1,2,…,e)在带权有向边<
Vj,Vk>
上,其持续时间用dur(<
Vj,Vk>
)表示,则有e[i]=Ve[j]
l[i]=Vl[k]-dur(<
Vj,Vk>
);
k=1,2,…,e
算法实现(以邻接表作存储结构)
从源点V1出发,令Ve[1]=0,按拓扑序列求各顶点的Ve[i]
从汇点Vn出发,令Vl[n]=Ve[n],按逆拓扑序列求其余各顶点的Vl[i]
根据各顶点的Ve和Vl值,计算每条弧的e[i]和l[i],找出e[i]=l[i]的关键活动
单源最短路径问题--迪杰斯特拉(Dijkstra)算法
按路径长度递增的次序产生最短路径算法
把V分成两组:
S:
已求出最短路径的顶点的集合
T=V-S:
尚未确定最短路径的顶点集合
将T中顶点按最短路径长度递增的次序加入到S中,保证:
从源点V0到S中各顶点的最短路径长度都不大于从V0到T中任何顶点的最短路径长度
每个顶点对应一个距离值
S中顶点:
从V0到此顶点的最短路径长度
T中顶点:
从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度
每对顶点之间的最短路径
假设求从顶点vi到vj的最短路径,弗洛伊德算法基本思想是:
如果从vi到vj有弧,则从vi到vj存在一条长度为cost[i][j]的路径,该路径不一定是最短路径,因为可能存在从vi到vj且包含其他顶点为中间顶点的较短路径。
尚需进行n次试探。
首先考虑路径(vi,v0,vj)是否存在。
如果存在,则比较(vi,vj)和(vi,v0,vj)的路径长度,取其中较短者为从vi到vj且中间顶点的序号不大于0的最短路径。
然后在路径上再增加一个顶点v1,设(vi,…,v1)和(v1,…,vj)分别是当前找到的从vi到v1和v1到vj中间顶点序号不大于0的最短路径,比较(vi,…,v0,…,vj)和(vi,…,v1)+(v1,…,vj)的路径长,取较短者作为从vi到vj且中间顶点的序号不大于1的最短路径。
再增加一个顶点v2,继续进行试探。
一般而言,若(vi,…,vk)和(vk,…,vj)分别是从vi到vk和从vk到vj的中间顶点的序号不大于k-1的最短路径,则将(vi,…,vk,…,vj)和已经得到的从vi到vj且中间顶点序号不大于k-1的最短路径相比较,取其长度较短者作为从vi到vj的中间顶点的序号不大于k的最短路径。
这样,在经过n次比较后,最后求得的必是从vi到vj的最短路径。
二、实现过程
实现代码的过程不是放在一个文件中,而是用头文件包含的形式,得把各个算法的实现代码放在不同额头文件中,用“#include”包含其中,但这有先后顺序,首先应该包含的是含有图的定义的代码和库文件,其次是各个菜单需要实现的代码,四种图的创建和显示,和基于两种存储结构的各种算法的实现,最后便是在主函数中调用和谐函数。
三、测试
第一层菜单显示界面
第二、三层菜单显示界面及输入
深度优先遍历
广度优先遍历
Prims算法演示
Kurskal算法演示
原图Kruscal得到最小生成树
拓扑排序运行:
关键路径
单源点的最短路径
不能把所有的代码都放在统一个源文件中,这样显得代码冗长且分析不易;
因此必须把各个算法的实现代码放在不同的头文件中,用#include把头文件包含其中,但这也有先后顺序,首先应该是包含状态结果的代码和库文件,接着是图的两种存储结构的定义,四种图的创建和显示,然后是基于两种存储结构的各种算法的实现,最后在主函数中调用这些功能函数即可。
有了实现的步骤,然后就是往其中写代码,进行测试。
由于书上的每个算法的代码都有,按照定义可将算法编写入每个功能模块当中。
在测试中也已经给出了详细的图和标准的输入实例,可以作为参考。
注意事项:
对于输入结点信息时,建议使用数字代号,且尽量与顶点的序号保持一致,例如:
在测试中原图为V1的点输入即为“1”。
不能输入字符或者标点。
五、难点与收获
在刚刚开始写程序时,根本无从下手,”Graph.h”都不会打开,更不会创建头文件,直到把老师已给的无向图的邻接矩阵和邻接表看懂了,才开始编写代码,而书上和附赠的光盘都有给出的伪代码,有些定义的方法尚未给出,还需要自己编译,这九天的数据结构课设是在摸石头过河和打破沙锅问到底的状态下完成的,我是在边看书边看PPT和网上求教边编程,尽管最后已经写到了关键路径,但是之后的单源点求最短路径和每队顶点之间的最短路径还是在老师和同学的帮助下才完成的。
这两天在机房里把数据结构编写出来,感觉自己在编程方面的水平有了较大幅度的提高,特别是原先对于链式存储十分模糊,现在慢慢的有了感觉知道他在计算机里面的存储方式和应用的优缺点。
图这一章的内容整体来说是整个数据结构里面的重点和难点,它的关系是多对多,对于计算机方面的应用是比线性表和树更为灵活的,所以掌握图的操作是十分必要的。
对于最后一个菜单有向网的操作是一个难点的操作,因为时间有限没有把迪杰斯特拉和弗洛伊德算法进行实现,而关键路径的算法也不是很熟悉。
如果时间再充沛些的我想后面难点的内容也能进行深一步的掌握和理解。
这是这几天编写数据结构我的收获和难点。
实现代码:
//***************************************
#include"
Graph.h"
#defineMAXVEX30
#defineMAXCOST1000
typedefintInfoType;
typedefstruct
{
VertexTypevexs[MAXVEX];
//一维数组存储图的结点
intarcs[MAXVEX][MAXVEX];
//二维数组存储图的弧或边信息
intvexnum,arcnum;
//vexnum顶点数目,arcnum边的数目
}MGraph;
//弧的结构类型
typedefstructarcnode
intadjvex;
//邻接点序号(位置)
intw;
//边或狐上的权值
InfoType*info;
structarcnode*next;
//递归定义下一条边
}ArcNode;
//邻接表(结点)的数据结构类型
typedefstructvnode
{
VertexTypedata;
//顶点信息
ArcNode*firstarc;
//指向下一个边结点
}Vnode,AdjList[MAXVEX];
//定义邻接(表)数据结构类型
AdjListvertices;
}ALGraph;
UDGraph.h"
CirQueue.h"
//包含队列文件,广度遍历时使用
voidCreatUDG_M(MGraph&
G)//创建无向图的邻接矩阵
inti,j,c;
cout<
<
"
请输入顶点数,边数:
;
cin>
>
G.vexnum;
G.arcnum;
请输入结点信息"
endl;
for(i=1;
i<
=G.vexnum;
i++)
cin>
G.vexs[i];
for(i=1;
i++)
for(j=1;
j<
j++)
G.arcs[i][j]=0;
//对图的边关系初始化
for(c=1;
c<
=G.arcnum;
c++)
{
cout<
第"
条边=>
起点序号,终点序号:
cin>
i>
j;
G.arcs[i][j]=1;
//无向图
G.arcs[j][i]=1;
//相同
}
cout<
创建的邻接矩阵为:
for(i=1;
i++)//将邻接矩阵打印出来
for(j=1;
cout<
G.arcs[i][j]<
"
邻接矩阵创建完毕"
}
voidCreatUDG_ALG(ALGraph&
G)//创建无向图的邻接表
inti,s,d;
ArcNode*p,*q;
//建立头结点
请输入顶点数,边数:
for(i=1;
{
G.vertices[i].data;
//输入结点的位置信息
G.vertices[i].firstarc=0;
}
s>
d;
p=(ArcNode*)malloc(sizeof(ArcNode));
//开辟结点空间
q=(ArcNode*)malloc(sizeof(ArcNode));
p->
adjvex=d;
q->
adjvex=s;
next=G.vertices[s].firstarc;
//p插入顶点s邻接表中
G.vertices[s].firstarc=p;
next=G.vertices[d].firstarc;
//q插入顶点d邻接表中
G.vertices[d].firstarc=q;
}
voidUDGdispgraph(ALGraphG)//创建的邻接表
inti;
ArcNode*p;
//头结点
图的邻接表表示如下:
\n"
["
"
G.vertices[i].data<
]->
p=G.vertices[i].firstarc;
//指向链接该结点的下一条弧
while(p!
=0)
p->
adjvex<
]→"
p=p->
next;
//弧指针下移
∧"
intVisited[MAXVEX];
//该点是否遍历的标示符
voidDFS(ALGraphG,intv)
//弧的头结点
G.vertices[v].data<
Visited[v]=1;
//该点已被遍历
p=G.vertices[v].firstarc;
//指向下一条弧
while(p!
=0)//有弧存在
if(Visited[p->
adjvex]==0)DFS(G,p->
adjvex);
p=p->
//指针后移
voidDFSTraverse(ALGraphG)
intv;
for(v=1;
v<
++v)
Visited[v]=0;
//初始化所有点未被遍历
if(Visited[v]==0)DFS(G,v);
voidBFS(ALGraphG,intv)
SeQueueQ;
//定义队列
//头结点
InitQueue(Q);
//建立
EnQueue(Q,v);
//第一点入队
while(!
QueueEmpty(Q))//队列不为空的话
DeQueue(Q,v);
//出队
p=G.vertices[v].firstarc;
//执行到协这,第一点已经遍历
while(p!
if(Visited[p->
adjvex]==0)
{
v=p->
adjvex;
G.vertices[v].data;
Visited[v]=1;
EnQueue(Q,v);
//将下一个临结点推入队列当中
}
voidBFSTraverse(ALGraphG)
if(Visited[v]==0)BFS(G,v);
UNGraph.h"
voidCreatUNG_M(MGraph&
G)//加权值若不相连,则距离为999
inti,j,k,n;
请输入顶点数和边数"
输入顶点"
++i)
++j)
G.arcs[i][j]=999;
//初始化不相连
G.arcs[i][i]=0;
//和自己之间的距离为0
for(k=1;
k<
++k)//构造邻接矩阵
起点序号,终点序号及权值:
j>
n;
G.arcs[i][j]=n;
G.arcs[j][i]=G.arcs[i][j];
//输出邻接矩阵
setw(8)<
G.arcs[i][j];
//格式控制符
voidCreatUNG_ALG(ALGraph&
G)//邻接表建立无向网
inti,s,d,w;
输入结点数和边数"
G.vexnum>
输入顶点序号"
++i)
{
//输入顶点信息(序号)
//首先初始化为空(没有邻接弧)
输入边的起点到终点的序号及权值"
d>
w;
//输入一条边依附的起点序号和终点序号
p=(ArcNode*)malloc(sizeof(ArcNode));
//开辟结点
q=(ArcNode*)malloc(sizeof(ArcNode));
p->
info=(InfoType*)malloc(sizeof(InfoType));
/q->
adjvex=d;
//保存该弧所指向的顶点位置
adjvex=s;
//同上
*(p->
info)=w;
//保存该点权值
*(q->
//下面的代码是将该结点插入的过程
//指针下移
voidUNGdispgraph(ALGraphG)//打印无向网每个结点的单链表
inti,j;
[起点权值终点]"
while(G.vertices[i].firstarc->
next){
//输出起点
j=G.vertices[i].firstarc->
->
*(G.vertices[i].firstarc->
info)<
G.vertices[j].data<
]"
//输出权值和终点
G.vertices[i].firstarc=G.vertices[i].firstarc->
j=G.vertices[i].firstarc->
cout<
voidPrim(MGraph&
G)
inti,j,k,min,lowcost[MAXVEX],closest[MAXVEX];
//代表一个标识符
for(i=2;
i++)//从顶点2开始
lowcost[i]=G.arcs[1][i];
closest[i]=1;
//在U-V集合里
closest[1]=0;
//在U的集合里
最小代价生成树的各条边为\n"
i++)//从U之外求离U中某一顶点最近的顶点
min=M