实验六 图遍历操作的实现
一、实验学时: 2学时
二、实验目的
- 实现图的基本操作
- 实现图的遍历操作
三、实验内容(2,3选做)
- 深度优先和广度优先搜索图
- 求图的关键路径
- 求图的最短路径
四、主要仪器设备及耗材
- 计算机一台
- VC++ 6.0,MSDN2003或者以上版本
五、实验步骤
- 分析问题
- 写出算法
- 编制程序
- 上机调试
- 分析结果
六、程序清单
#include<iostream>
#include "自己的链队.h" //这里导入自己写的头文件
using namespace std;
//最大顶点数
#define MVNum 100
//定义边表
typedef struct ArcNode
{
int adjvex; //邻接点
struct ArcNode *nextarc; //链域(下一条边的指针)
int info; //数据域(权值)
}ArcNode;
//定义表头结点表
typedef struct VNode
{
char data; //数据域(存放顶点信息)
ArcNode *firstarc; //指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum]; //邻接表
//定义图
typedef struct
{
AdjList vertices; //邻接表
int vexnum,arcnum; //图的当前顶点数和边数
}ALGraph;
//查找顶点u在图G中的位置
int LocateVex(ALGraph G,char u)
{
for(int i=0;i<G.vexnum;++i) //遍历顶点信息
if(u==G.vertices[i].data) return i; //若顶点u在图G中被找到则返回位置i
return -1; //顶点u在图中不存在返回-1
}
//采用邻接表表示法创建无向图
int CreateUDG(ALGraph &G)
{
cout<<"请输入顶点数 总边数:";
cin>>G.vexnum>>G.arcnum;
for(int i=0;i<G.vexnum;++i) //遍历输入顶点值,其实可以在一行输入我的截屏中是在多行输入的
{
cout<<"请输入顶点值:";
cin>>G.vertices[i].data;
G.vertices[i].firstarc=NULL; //每个顶点结点的表置为空,执行到这里时只有顶点还没有边
}
for(int k=0;k<G.arcnum;++k) //遍历添加边信息
{
int i,j;
char v1,v2;
ArcNode *p1,*p2;
cout<<"请输入一条边依附的两个顶点:";
cin>>v1>>v2;
i=LocateVex(G,v1); j=LocateVex(G,v2); //找出这两个点在图中的位置信息
p1=new ArcNode; //创建一个边结点
p1->adjvex=j; //这条边的邻接点置为j
p1->nextarc=G.vertices[i].firstarc; G.vertices[i].firstarc=p1; //将指向p1的下一条边的指针指向图中位置在i的顶点的表的第一个地址,将位置在i的顶点的表的第一个地址指向p1,就是每一次都将新边加在顶点结点表的最前边
p2=new ArcNode;
p2->adjvex=i; //这条边的邻接点置为i
p2->nextarc=G.vertices[j].firstarc; G.vertices[j].firstarc=p2;//同p1
}
return 0;
}
bool visited[MVNum]; //标记访问情况的数组
//对邻接表表示的图的深度优先遍历
void DFS_AL(ALGraph G,int v)
{
cout<<G.vertices[v].data;visited[v]=true; //输出位置v的顶点信息,并把visited数组的相应位置改为true表示访问过了
ArcNode *p;int w;
p=G.vertices[v].firstarc; //p指向顶点v的邻接点域
while(p!=NULL) //若邻接点域非空则循环
{
w=p->adjvex; //w是p的v的邻接点在图中的位置
if(!visited[w]) DFS_AL(G,w); //若w位置的顶点未被访问,则递归遍历
p=p->nextarc; //p指向下一条边
}
}
//查找顶点v的邻接点在图G中的位置
int FirstAdjVex(ALGraph G,int v)
{
return G.vertices[v].firstarc->adjvex; //因为我做的无向图、连通图所以一定有邻接点就不判断了
}
//查找顶点u的下一个邻接点(相对于w而言)在图G中的位置
int NextAdjVex(ALGraph G,int u,int w)
{
ArcNode *p=G.vertices[u].firstarc;
while(p->nextarc!=NULL) //若u的邻接点有下一条边
{
if(p->adjvex==w) return p->nextarc->adjvex; //这是找顶点u的下一个邻接点
p=p->nextarc; //p指向下一条边
}
return -1; //若u的邻接点都被访问过了就返回-1表示这个顶点的所有邻接点都访问了
}
//广度优先搜索遍历连通图
void BFS(ALGraph G,int v)
{
cout<<G.vertices[v].data;visited[v]=true; //输出位置v的顶点信息,并把visited数组的相应位置改为true
LinkQueue Q; //建一个链队
InitQueue(Q);
EnQueue(Q,v); //v入队
while(Q.front!=Q.rear) //若队列非空
{
int u;
DeQueue(Q,u); //u出队
for(int w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w)) //w等于u的邻接点的位置,然后循环依次找下一个邻接点位置
if(!visited[w]) //若w位置的顶点未被访问
{
cout<<G.vertices[w].data;visited[w]=true; //输出w位置的顶点,并把visited数组的相应位置改为true
EnQueue(Q,w); //w入队
}
}
}
int main()
{
ALGraph g;
CreateUDG(g); //创建邻接表表示的无向图
cout<<"深度优先搜索的结果是:";
DFS_AL(g,0);
cout<<endl;
for(int i=0;i<MVNum;i++) //因为深度遍历把所有结点都访问过了,现在把标记访问情况的结点初始化
visited[i]=false;
cout<<"广度优先搜索的结果是:";
BFS(g,0);
}
七、运行结果及分析
八、小总结
因为邻接表是无向图的一种很有效的存储结构,在邻接表中容易求得顶点和边的信息,所以我选用了邻接表来练习存储无向图,它的时间复杂度为O(n+e)。
建立无向图上面代码注释部分已经说了,这里再提一下DFS和BFS。DFS就是来一个顶点看它有未访问的邻接点没,有的话就开始递归,最后一个都访问过后开始递归的返回阶段。BFS就是跟树的层级遍历很像,一层一层的,就用队列来帮助一下,有未被访问的邻接点的顶点就在队里待着,都访问过了就出队。这样就能保证一层一层的。