图的遍历(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)
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/15163656.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步