图遍历操作的实现

实验六 图遍历操作的实现

一、实验学时: 2学时

二、实验目的

  1. 实现图的基本操作
  2. 实现图的遍历操作

三、实验内容(2,3选做)

  1. 深度优先和广度优先搜索图
  2. 求图的关键路径
  3. 求图的最短路径

四、主要仪器设备及耗材

  • 计算机一台
  • VC++ 6.0,MSDN2003或者以上版本

五、实验步骤

  1. 分析问题
  2. 写出算法
  3. 编制程序
  4. 上机调试
  5. 分析结果

六、程序清单

#include
#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);
} 

七、运行结果及分析
图遍历操作的实现_第1张图片
八、小总结
因为邻接表是无向图的一种很有效的存储结构,在邻接表中容易求得顶点和边的信息,所以我选用了邻接表来练习存储无向图,它的时间复杂度为O(n+e)。
建立无向图上面代码注释部分已经说了,这里再提一下DFS和BFS。DFS就是来一个顶点看它有未访问的邻接点没,有的话就开始递归,最后一个都访问过后开始递归的返回阶段。BFS就是跟树的层级遍历很像,一层一层的,就用队列来帮助一下,有未被访问的邻接点的顶点就在队里待着,都访问过了就出队。这样就能保证一层一层的。

你可能感兴趣的:(数据结构,数据结构,bfs,dfs)