图的顶点查找问题——图的遍历04

图的广度优先遍历 BFS

广度优先搜索算法,又称广度优先搜索算法,是连通图的一种遍历策略,也是最简单的图的搜索算法之一。Dijksta 单源最短路径算法和 Prim 最小生成树算法都采用了与宽度优先搜索类似的思想。

基本思想
在这里插入图片描述
伪代码描述
(1)顶点v入队列。
(2)当队列非空时则继续执行,否则算法结束。
(3)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。
(4)查找顶点v的第一个邻接顶点w。
(5)若v的邻接顶点w未被访问过的,则w入队列。
(6)继续查找顶点v的另一个新的邻接顶点w,转到步骤(5)。
直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。
伪代码的细化描述

设立一个访问标志数组visited[N],初值为0,某顶点被访问后,则相应下标元素置1。
(1)初始化队列Q;visited[N]=0;
(2)访问顶点v;visited[v]=1;顶点v入队列Q;
(3) while(队列Q非空)
v = 队列Q的队头元素出队;
w = 顶点v的第一个邻接点;
while ( w存在 )
如果w未访问,则访问顶点w;
visited[w]=1;
顶点w入队列Q;
w=顶点v的下一个邻接点。

(邻接矩阵的 BFS实现)

#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define N 9 //顶点数
int Visited[N];
int AdjMatrix[N][N]=//邻接矩阵
	{{0,1,0,0,0,0,0,0,0},
	{1,0,0,0,1,1,0,1,1}, 
	{0,0,0,0,0,1,1,0,0}, 
	{0,0,0,0,1,0,0,0,1}, 
	{0,1,0,1,0,1,1,0,1}, 
	{0,1,1,0,1,0,1,0,0}, 
	{0,0,1,0,1,1,0,0,0}, 
	{0,1,0,0,0,0,0,0,0}, 
	{0,1,0,1,1,0,0,0,0}};
/*==========================================
函数功能:找顶点v相邻点i的后一个相邻点
函数输入:顶点v,v的相邻点i
函数输出:i的后一个相邻点下标,无相邻点时返回-1
=============================================*/
int FindVex(int v,int i)
{
	while (AdjMatrix[v][i]==0) i++;     
	if (i<N) return i;
	else return -1; 
}

/*==========================================
函数功能:基于邻接矩阵的BFS遍历
函数输入:图的遍历起始顶点v
函数输出:无
屏幕输出:图的BFS序列
=============================================*/
void GraphBFS(int v)
{
	int flag;
	SeqQueue struc;
	SeqQueue *sq;
	sq=&struc;
	int w,k;
	int count=0;

	initialize_SqQueue(sq);
	printf("BFS序列:");
	printf("%d ",v);
	Visited[v]=1;
	count++;
	flag=Insert_SqQueue(sq,v);			//首结点入队
	while (!Empty_SqQueue(sq))			//队列Q非空
	{
		if (count==N) break;
		k=Delete_SqQueue(sq);			//队列Q的队头元素出队,返回元素下标位
		v=sq->data[k];
		w=FindVex(v,0); 				//w=顶点v的第一个邻接点;
		while(w!=-1)
		{
            if( Visited[w]!=1)				//如果w未访问过
		   {
			   Visited[w]=1;			//置w访问标记
			   printf("%d ",w);
			   count++;
		   }
		       flag=Insert_SqQueue(sq,w);	//顶点w入队列Q
                 w=FindVex(v,w+1);		//w=顶点v的下一个邻接点
		}
	}
	printf("\n");
}

int main()
{
	GraphBFS(0);//从顶点1开始遍历,对应下标为0
	return 0;
}

int k 取 -被删结点下标。
队列中也始终是1或0个结点。

BFS算法讨论

广度优先搜索算法解题的步骤:

1)定义一个状态结点

采用广度优先搜索算法解题问题时,需要构造一个标明状态特征和不同状态之间关系的数据结构。

2)确定结点的扩展规则

根据问题所给定的条件,从一个结点出发,可以生成一个或多个新的结点,这个过程通常称为扩展。搜索结果中的结点之间的关系一般可以表示成一棵树,称为解答树。搜索算法的搜索过程实际上就是根据初始条件和扩展规则构造一棵解答树。搜索算法的搜索过程实际上就是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的结点的过程。

广度优先搜索算法中,解答树上结点的扩展是按它们接近起始结点的程度依次进行的。首先生成第一层接地那,同时检查目标结点是否在所生成的结点中,如果不在,则将所有的第一层结点逐一扩展,得到第二层结点,并检查第二层结点是否包含目标结点,…对 n+1 层结点进行扩展之前,必须先考虑 n 层结点的每种可能的状态。因此,对于同一层结点来说,求解问题的价值是相通的,我们可以按任意顺序来扩展它们。这里采用的原则是先生成的结点先扩展。

3)搜索策略

为了便于进行搜索,要设置一个表存储所有的结点。因为在广度优先搜索算法中,要满足先生成的结点先扩展的原则,所以存储结点的表一般设计成队列的数据结构。
搜索的步骤一般是:
(1)从队列头取出一个结点,检查它按照扩展规则是否能够扩展,如果能则产生一个新结点。
(2)检查新生成的结点,看它是否已在队列中存在,如果新结点已经在队列中出现过,就放弃这个结点,然后回到第(1)步。否则,如果新结点未曾在队列中出现过,则将它加入到队列尾。
(3)检查新结点是否目标结点。如果新结点是目标结点,则搜索成功,程序结束;若新结点不是目标结点,则回到第(1)步,再从队列头取出结点进行扩展。
搜索最终可能产生两种结点:找到目标结点,或扩展完所有结点而没有找到目标结点。
如果目标结点存在于解答树的有限层上,广度优先搜索算法一定能保证找到一条通向它的最佳路径,因此广度优先搜索算法特别适用于只需求出最优解的问题。当问题需要给出解得路径,则要保存每个结点的来源,也就是它是从哪一个结点扩展来的。

广度优先算法需要从初始结点出发,逐步扩展才能找到问题的解。如果问题有解,它总是处在解答树的某一层上。
在这里插入图片描述

图的深度优先遍历 DFS

图的深度优先搜索,类似于树的先序遍历,所遵循的搜索策略是尽可能“深”地搜索图。
如果它还有以此为起点而未探测到的边,就沿此边继续探寻下去。一直进行到已发现从源节点可达的所有结点为止。
在这里插入图片描述
在这里插入图片描述
DFS 算法分析
在这里插入图片描述
由于没有规定访问邻接点的顺序,深度优先序列不唯一。

DFS算法描述:
在这里插入图片描述
注:以上为连通图的 DFS 算法。非连通图的 DFS算法在上述连通图的算法基础上再检查是否有剩余顶点,如果仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复 DFS 过程,直至图中所有顶点均已被访问为止。

基于邻接矩阵的 DFS 递归方法程序实现

/*==========================================
函数功能:基于邻接矩阵的图DFS遍历递归算法
函数输入:图的遍历起始顶点v
函数输出:无
屏幕输出:图的DFS序列
=============================================*/
void GraphDFS(int i) 
{  int j;
   printf("%d ",i+1); //i+1是因为图中顶点编号从1开始,存储从0开始
   Visited[i]=1;
   for (j=0; j<N; j++)
         if ((AdjMatrix[i][j]==1) && (!Visited[j]) )
             GraphDFS(j);  		//被调用n次
}

基于邻接表的DFS递归方法程序实现
在这里插入图片描述

/*==========================================
函数功能:基于邻接表的DFS遍历递归算法
函数输入:图的遍历起始顶点v
函数输出:无
屏幕输出:图的DFS序列
=============================================*/
void GraphDFS_L(int vi)	
//从vi出发深度优先搜索遍历图,图用邻接表表示
{	AL_AdjNode *p;
	printf("%d ",VexList[vi].vertex+1);	//访问顶点vi  
	Visited[vi]=1;            	//标记vi已被访问 
	p=VexList[vi].link;       	//取vi的边表头指针 
	while( p!=NULL )          	//依次搜索vi的邻接点 
	{
	  if (Visited[p->adjvex]==0)
	  //从vi的未曾访问过的邻接点出发进行深度优先搜索遍历
        GraphDFS_L(p->adjvex);  
	    p=p->next;
	}
} 

过程:访问(打印)->在邻接点递归
找邻接点(全部都在边表)并打印它,while循环条件内可增设一计数变量作为结束标志。

基于邻接表的非递归方法程序实现

/*==========================================
函数功能:图的DFS遍历非递归算法
函数输入:图的遍历起始顶点vi
函数输出:无
屏幕输出:图的DFS序列
=============================================*/
void DFS(int vi)
{
	SeqStack struc;
	SeqStack *s;
	int vj; 
	int flag;
	
	s=&struc;	
	initialize_SqStack( s );				//栈初始化
	Visited[vi]=1;						//访问顶点vi
	 printf("%d ",vi+1);
	flag=Push_SqStack(s,vi);				//顶点vi入栈
	while(!StackEmpty_SqStack(s))			//栈非空
	{
		vj=0;
     	flag=Get_SqStack(s, &vi);			//vi=栈顶元素(不出栈)
		//vi有邻接点且未被访问,跳出
        	while(!(AdjMatrix[vi][vj]==1 && Visited[vj]==0)) vj++;
         	if (vj<N) //访问vj
		{
			printf("%d ",vj+1);
			Visited[vj]=1;
             	flag=Push_SqStack(s,vj);		//vj进栈;
		 }
         else
		{
             flag=Pop_SqStack(s, &vi);		//vi出栈;
		}
	}
}

测试用图

需先把邻接矩阵转换成邻接表或手动输入邻接表

AdjMatrix[N][N]=
{{0,1,1,0,0,0,0,0},
{1,0,0,1,1,0,0,0},
{1,0,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1},
{0,1,0,0,0,0,0,1},
{0,0,1,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,1,0,0,0}};
在这里插入图片描述

图的遍历问题分类

遍历完所有的边而不能有重复,即所谓“一笔画问题”或“欧拉路径”;
遍历完所有的顶点而没有重复,即所谓“哈密尔顿问题”;

遍历完所有的边可以有重复,即所谓“中国邮递员问题”;
遍历完所有的顶点而可以重复,即所谓“旅行推销员问题”。

图的遍历小结
在这里插入图片描述

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值