图的广度优先遍历和深度优先遍历

一.图的表示                                                                                                                     

1.邻接表

    一般用来表示稀疏图(边的条数|E|远远小于|V|^2)可以对其进行简单修改来支持许多其他的图的变种。邻接表的缺陷是无法快速的的判断一条边(u,v)是否是图中的一条边,唯一的办法是在邻接表[u]里面搜索节点v。邻接表表示法的储存空间需求为Q(V+E)。                                                                                                                                                     

2.邻接矩阵

   一般用来表示稠密矩阵(|E|接近|V|^2),表示法简单,可以比较快的判断一条边(u,v)是否属于图,储存空间需求为Q(V^2)。在图的规模比较小的时候一般倾向于邻接矩阵表示法。

                                                    

二.图的遍历                                                   

1.广度优先遍历(BFS)

   (1)给定一个图(V,E)和一个节点S后,BFS可以用来找到从S可到达的所有节点,以及S到每个节点的最小距离(最少的边数),并生成一颗广度优先搜索树。BFS需要在找到距离S最小距离为K的所有节点后,才开始找距离S为K+1的节点。

   (2)算法实现                        

int BFS(int ** G,int n,int s)    //G用于接收邻接矩阵,n为节点数,s为遍历初始点
{
	
	int *YBL=new  int [n];       //YBL数组用于标记遍历过的点,若Vi节点遍历过YBL[i]=1,否则YBL[i]=0;
	for(int i=0;i<n;i++)
		 YBL[i]=0;
	YBL[s]=1;                   //给初始节点已经遍历标记
        int **JG=new int*[n];       //JG用于保存遍历结果
	for(int i=0;i<n;i++)        //JG[i][0]储存节点下标,JG[i][1]储存节点距离初始遍历点的距离
		JG[i]=new int[3];       //JG[i][2]生成遍历树中节点的父节点
	JG[0][0]=s,JG[0][1]=0,JG[0][2]=-1;   //初始节点S加入到JG,S距离初始节点0,S的父节点-1(不存在)
	int hig=1;                           //hig等于当前JB中保存节点个数
	for(int i=0;i<hig;i++)               //对JB中保存的节点从前到后遍历,一次找到与他们相连接的节点,并加入JB     
	{
		for(int j=0;j<n;j++)
		{
			if((*((int*)G+n*JG[i][0]+j))&&(YBL[j]==0))//若节点JG[i][0]与节点j连通,且J节点未被遍历
			{
				JG[hig][0]=j;                         //把j节点加入JG中
				JG[hig][1]=JG[i][1]+1;                //j节点距初始节点距离等于JG[i][0]节点到初始节点距离加1
				JG[hig][2]=JG[i][0];                  //j节点的父节点为JG[i][0]
				hig=hig+1;                            //JB中保存的节点加1
				YBL[j]=1;                             //给j节点做已遍历标记
			}
		}
		YBL[i]=1;
	}
	for(int i=0;i<n;i++)                              //输出结果
	{
		cout<<"V"<<JG[i][0]<<"距离节点V"<<s<<":"<<JG[i][1]<<"   广度优先搜索树父节点是:V"<<JG[i][2]<<endl;
	}
	delete YBL;
	delete [] JG;
	return 0;
}
   (3)举例:

                                                        

         

int main()
{
	int G[7][7] =   {{0,1,1,0,0,0,0},        //上图
			 {1,0,0,1,0,0,0},
			 {1,0,0,0,1,0,0},
			 {0,1,0,0,0,1,1},
			 {0,0,1,0,0,1,1},
		   	 {0,0,0,1,1,0,1},
		         {0,0,0,1,1,1,0}};
	
	BFS((int **)G,7,1);
	return 0;
}
            结果:

                        

                         V-1表示在生成的广度遍历树中V1没有父节点,既V1是根节点

2.深度优先遍历(DFS)

(1)优先深度优先总是对最近才发现的节点V进行探索,直到该节点的所有出发边都被发现为止。一旦节点V的所有出发点都被发现,搜索则”回溯“到V的前驱结点(V是经过该节点才被发现的)

 (2)算法实现(DFS)

int DFS(int **G,int n,int s)                 //G用于接收邻接矩阵,n为节点数,s为遍历初始点</span></span>
{
	int  F_DFS(int **G,int n,int*YBL,int *JG);
	int *YBL=new int[n];                 //用于标记已遍历过的节点数
	for(int i=0;i<n;i++)
		YBL[i]=0;
	YBL[s]=1;
	int *JG=new int [n];
	for(int i=0;i<n;i++)
		JG[i]=0;
	JG[0]=s;                            //用来按顺序保存遍历得点
	F_DFS(G,n,YBL,JG);
	return 0;
}

int F_DFS(int **G,int n,int*YBL,int *JG)
{ 
	static int len=0;                  //用来保存遍历的个数
	static int temp=0;                 //用来表示当前检查(遍历)的点
  		if(len>=n-1)
		{
			
			return 0;
		}
		else
		{
		    int flag=1;
			for(int i=0;i<n;i++)
			{	if(((*((int *)G+JG[temp]*n+i))==1)&&(YBL[i]==0))
				{
					flag=0;
					cout<<JG[temp]<<"---"<<i<<endl;
					YBL[i]=1;
					len=len+1;
					JG[len]=i;
					if(temp==0)           //重要,当回溯到起始节点时,若还有下一个点可遍历,会被存在JG[len]中,
						temp=len;     //下一次遍历是用JG[len]做起点,而不是Len[1];
					temp=temp+1;          //但这样有一个问题当再次回溯到JG[len-1]时,因为temp=len-1会对JG[len-1...0]节点再次检查
					                      //但是不影响结果,因为与JG[len-1...0]节点相连的点已被标记为遍历过,所以不会再次遍历
					if(len==n-1)          //若不用对结果做记录,出现一个节点就输出到屏幕一个,
					for(int i=0;i<n;i++)  //既用栈的思想来处理,就可以解决这个问题
							cout<<JG[i]<<"   ";
					F_DFS(G,n,YBL,JG);
				}
			}
			if(flag==1)
			{
			temp=temp-1;
			F_DFS(G,n,YBL,JG);
			}
				
			
		}
}
(3)举例

                                                                         

int main()
{
	int G[7][7] =          {{0,1,1,0,0,0,0},        //上图
			        {1,0,0,1,0,0,0},
			        {1,0,0,0,1,0,0},
			        {0,1,0,0,0,0,1},
			        {0,0,1,0,0,1,0},
		   	        {0,0,0,0,1,0,0},
		                {0,0,0,1,0,0,0}};
	
	DFS((int **)G,7,1);
	return 0;
}
        结果:



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值