图的遍历(DFS、BFS)
深度优先遍历(DFS)
思想:
一条路走到底:走到访问过的结点,退回上一结点;从上一结点开始,继续遍历未访问的结点,重复此项工作。(遍历次序可能不同)
案例:根的先根遍历
代码(邻接矩阵)(连通图)
代码思想:每次取出一个元素,放入与该元素相连的并且没有放入栈中的其他结点;直到无路可走,只取栈中元素。
(伪)代码:
void DFS(AMGraph G,int v)//v起始顶点
{
int Visited[AMGraph.vexnum];//辅助数组:记录节点有没有被访问过
memset(Visited,0,sizeof(Visited));//0代表未访问过
cout<<v ; Visited[v]=1;
for(int w=0;w<G.vexnum;w++)
{
if(G.arcnum[v][w]!=0&&(!Visited[w]))
DFS(G,w);
//w是v的邻接点,如果w未访问,则递归调用DFS
}
}
对于非连通图:遍历完一个连通分量后,再遍历另一个连通分量
代码(C++模拟邻接表)(连通图)
#include <bits/stdc++.h>
using namespace std;
const int Int = 2e5+5;
vector<int> graph[Int];//可变数组模拟邻接表
int visited[Int];//记录该点是否遍历过
int n,m;//n个顶点,m条边
void DFS(int key)
{
cout<<key<<' ';
visited[key]=1;
int i;
int len=graph[key].size();
for(i=0; i<len; i++)
{
int o=graph[key][i];
if(visited[o]==0)
{
DFS(o);
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(graph,0,sizeof(graph));//初始化
memset(visited,0,sizeof(visited));//初始化
cin>>n>>m;//n个顶点,m条边
int i;
int a,b;
for(i=0; i<m; i++)
{
cin>>a>>b;
graph[a].push_back(b);
graph[b].push_back(a);
}
for(i=1; i<=n; i++)//从小到大排序
{
sort(graph[i].begin(),graph[i].end());
}
DFS(0);//从0开始遍历
cout<<endl;
}
return 0;
}
实战
一. 模板题
#include <iostream>
#include <string.h>
using namespace std;
int visit[100];//记录结点有没有被访问过
int k,m;
int Map[100][100];//数据图
void DFS(int x)
{
int j;
for(j=0; j<k; j++)
{
if(visit[j]==0&&Map[x][j]==1)
//找到当前节点下一个未被遍历且有边相连的节点//
{
visit[j]=1;
cout<<" "<<j;
DFS(j);
}
}
}
int main()
{
int n;
cin>>n;
while(n--)
{
memset(Map,0,sizeof(Map));
memset(visit,0,sizeof(visit));
cin>>k>>m;
int i;
int u,v;
for(i=0; i<m; i++)
{
cin>>u>>v;
Map[v][u]=Map[u][v]=1;
//这是无向图别忘了对称位置也要赋值
}
visit[0]=1;//一定先访问0节点,故预处理
cout<<0;//一定先访问0节点,故预处理(方便处理输出格式)
DFS(0);
cout<<endl;
}
return 0;
}
#include <iostream>
#include <string.h>
using namespace std;
int flag=0;
int visit[202][202];//记录结点有没有被访问过
int n,m;//n行m列
char Map[202][202];//数据图
//四方搜索
void DFS(int x,int y,int xl,int yl)
//x1,y1记录上一次走过的位置
{
visit[x][y]=1;//走过的就不再走了
if(flag==1) return;
/*
如果不越界并且map == 某方向前进一格后的map
{
如果前进一格的map被访问过,并且不是上一个被访问过的结点
那么就是有环
否则:
如果前进一格的map没有被访问过,则DFS该点
}
*/
if(y-1>=0&&Map[x][y-1]==Map[x][y])
{
if(visit[x][y-1]==1&&(x!=xl||y-1!=yl))
{
flag=1;
}
else if(visit[x][y-1]==0)
{
DFS(x,y-1,x,y);
}
}
if(y+1<m&&Map[x][y+1]==Map[x][y])
{
if(visit[x][y+1]==1&&(x!=xl||y+1!=yl))
{
flag=1;
}
else if(visit[x][y+1]==0)
{
DFS(x,y+1,x,y);
}
}
if(x+1<n&&Map[x+1][y]==Map[x][y])
{
if(visit[x+1][y]==1&&(x+1!=xl||y!=yl))
{
flag=1;
}
else if(visit[x+1][y]==0)
{
DFS(x+1,y,x,y);
}
}
if(x-1>=0&&Map[x-1][y]==Map[x][y])
{
if(visit[x-1][y]==1&&(x-1!=xl||y!=yl))
{
flag=1;
}
else if(visit[x-1][y]==0)
{
DFS(x-1,y,x,y);
}
}
}
int main()
{
while(cin>>n>>m)
{
int i,j;
for(i=0; i<n; i++)
{
cin>>Map[i];
}
memset(visit,0,sizeof(visit));
flag=0;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(visit[i][j]==0)
{
DFS(i,j,i,j);
}
if(flag==1)
{
break; //剪枝
}
}
if(flag==1)
{
break; //剪枝
}
}
if(flag==1)
{
cout <<"Yes"<<endl;
}
else
{
cout <<"No"<<endl;
}
}
return 0;
}
三. 数据结构实验之栈与队列十:走迷宫
和二. 类似
这名字起的......,题目和名字没有关系
#include <iostream>
#include <string.h>
using namespace std;
int add=0;//累加器
int visit[112][112];//记录结点有没有被访问过
int n,m;//n行m列
int graph[112][112];//数据图
//四方搜索
void DFS(int x,int y)
{
if(graph[x][y]==1) return;
if(visit[x][y]==1) return;
if(x==n-1&&y==m-1)
{
add++;
}
else
{
if( x < 0 || x >= n
||y < 0 || y >= m
||graph[x][y] == 1)
return ;
if(visit[x][y] == 0)
{
visit[x][y] = 1;
DFS(x + 1, y);
DFS(x, y + 1);
DFS(x - 1, y);
DFS(x, y - 1);
visit[x][y] = 0;
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
cin>>graph[i][j];
}
}
add=0;
memset(visit,0,sizeof(visit));
DFS(0,0);
cout<<add<<endl;
}
return 0;
}
广度优先搜索(BFS)
思想:
先访问完一个节点的所有邻接点,然后按照邻接点的被访问顺序,重复此过程,直到所有节点都被访问。
类似于:树的层次遍历
代码
代码思想:每次取出一个元素,放入与该元素相连的其他结点
伪代码:
Code
void BFS(ALGraph G,int v)//非递归
{
int visited[G.vexnum];//用作该节点有没有被访问过
memset(visited,0,sizeof(visited));
//
cout<<v;
visited[v]=1;
//
initQueue(Q);//初始化队列Q
EnQueue(Q,v);//v进队
while(!QueueEmpty(Q))//队列非空
{
DeQueue(Q,u);//队头元素出队并置为u
for(int w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
{
if(!visited[w])
{
cout<< w;
visited[w]=1;
EnQueue(Q,w);//w进队
}
}
}
}
c++代码(非递归实现):
#include<bits/stdc++.h>
using namespace std;
queue<int> Q;//队列
int n,m,k;//n个点,m条边,出发点为k
int graph[50][50];//图
int visited[50];//标记走没走过
void BFS(int v)
{
Q.push(v);
visited[v]=1;
while(!Q.empty())
{
int o;
o=Q.front();
Q.pop();
cout<<o<<" ";
for(int i=0;i<=n;i++)
{
if(visited[i]==0&&graph[o][i]==1)
{
Q.push(i);
visited[i]=1;
}
}
}
}
int main()
{
int t;
cin>>t;//t组数据
while(t--)
{
memset(graph,0,sizeof(graph));
memset(visited,0,sizeof(visited));
cin>>n>>m>>k;//n个点,m条边,出发点为k
int x,y;
int i;
for(i=0;i<m;i++)
{
cin>>x>>y;
graph[x][y]=graph[y][x]=1;
}
BFS(k);
cout<<endl;
}
return 0;
}
邻接矩阵时间复杂度:O(n²)
邻接表时间复杂度O(m+e)
空间复杂度O(n)