图的遍历及应用--广度遍历、深度遍历、单源最短路径

图的遍历:指从图的某一顶点出发,按照某种搜索方法沿着图中的边,对所有节点访问一次且仅一次。

图的遍历主要有两种算法:广度优先遍历和深度优先遍历

这两种遍历算法,我在考研期间有复习过,所以现在写到博客上(算法的实现前提是都是基于图的邻接表的存储方式存储的)

我们知道,通常图的存储方式有两种:邻接矩阵和邻接表,本篇中的存储方式则是基于邻接表的方式存储的。

存储结构

typedef struct ArcNode{//边表结点
	int adjex;//该边所指向的下一个顶点的位置
	struct ArcNode *next;//指向下一条边的指针
}ArcNode;
typedef struct VNode{
     int data;//存放顶点信息
	 ArcNode *firstarc;//指向第一个边表结点的指针
}VNode,Adjlist[50];
typedef struct{
	Adjlist adjlist;//存放顶点表的数组
	int vernum,arcnum;//存放的顶点数和边数
}Graph;

图的广度优先遍历

思想

首先给定访问的初始顶点v,由该顶点v出发,依次访问与它相邻且未访问过的节点w1,w2,w3........wi,直至访问完。然后再依次访问与w1相邻且未访问过的节点,以此类推,直至所有的节点都访问过了。

实现代码

#include<iostream>
#include<queue>
using namespace std;

bool visited[50];
//该算法是使用到了图的邻接表的存储方法实现的

typedef struct ArcNode{//边表结点
	int adjex;//该边所指向的下一个顶点的位置
	struct ArcNode *next;//指向下一条边的指针
}ArcNode;
typedef struct VNode{
     int data;//存放顶点信息
	 ArcNode *firstarc;//指向第一个边表结点的指针
}VNode,Adjlist[50];
typedef struct{
	Adjlist adjlist;//存放顶点表的数组
	int vernum,arcnum;//存放的顶点数和边数
}Graph;
void visit(Graph G,int v){
	cout<<"现在访问的节点是"<<(G.adjlist[v]).data<<endl;
}
//广度优先遍历
void BFS(Graph G,int v){
  visit(G,v);//访问起始结点v
  visited[v]=true;//置访问标记
  queue<int> q;//声明定义队列q
  q.push(v);//将已访问过的顶点v入队列
  while(!q.empty()){//队列不为空时
     v=q.front();//取队首元素
	 q.pop();//出队列
	 ArcNode *p=(G.adjlist[v]).firstarc;//p指向其第一个边表结点处
	 while(p){//p不为空时
		 if(!visited[p->adjex]){//该顶点未被访问过时
			 visit(G,p->adjex);
			 visited[v]=true;
			 q.push(p->adjex);
		 }
		 else p=p->next;//若该边已被访问过,则指向下一条
	 }
  }
}
void BFS_Traverse(Graph G){
	int i;
	for(i=0;i<G.vernum;i++){
		visited[i]=false;
	}
	for(int j=0;j<G.vernum;j++){
		if(!visited[j]){
		BFS(G,i);}
	}
}

同时,基于广度优先遍历的实例也有很多,比如求单源最短路径(即求从一个顶点出发,到其它顶点的最短路径问题)

思想:

设置数组d[i]用于记录到每个顶点的距离,开始时将其初始化为无穷大,并设置起始顶点的d[v]=0,利用广度优先遍历算法,所有与v顶点相邻接的顶点i,d[i]=d[v]+1;以此类推,具体实现如下:

//单源最短路径
void BFS_Min(Graph G,int v){
	int d[50];
	for(int i=0;i<G.vernum;i++){//置数组中的每个元素的d[i](标识距离)都为无穷大
	   d[i]=9999;
	}
	visit(G,v);
	visited[v]=true;
	d[v]=0;//因为是计算的v到其他节点的距离,所以v到自己的距离为0
	queue<int> q2;
	q2.push(v);
	while(!q2.empty()){
	  v=q2.front();
	  q2.pop();
	  ArcNode *p2=(G.adjlist[v]).firstarc;//指向第一个边表结点
	  if(p2){
		  visit(G,p2->adjex);
		  visited[p2->adjex]=true;
		  d[p2->adjex]=d[v]+1;
		  q2.push(p2->adjex);
	  }
	  else p2=p2->next;
	}
}

深度优先遍历算法:

思想

尽可能深的搜索,由起始顶点v出发,访问与v邻接且未被访问的任意顶点w1,再访问与w1邻接且未被访问的任意顶点w2,依次访问,直至全部都访问到。

我们采用递归的方式实现,先访问起始顶点,并置访问标记,定义指针p指向该节点的第一个边表结点

当p未被访问过时,递归调用DFS算法进行访问,当p已被访问过,则执行p=p->next,移到下一个边表结点。

实现:

//深度优先遍历
//采用递归的方法实现
void DFS(Graph G,int v){
  visit(G,v);
  visited[v]=true;
  ArcNode *p=(G.adjlist[v]).firstarc;//定位到第一个边表结点
  if(!visited[p->adjex]){//如果改变没有访问过,则递归调用dfs访问
	  DFS(G,p->adjex);
  }
}

以上就是图的遍历的两种算法的实现

猜你喜欢

转载自blog.csdn.net/qq_40170007/article/details/88075592