图的遍历是指对图中的顶点按照一定的顺序进行访问。
图的遍历一般分为两种:DFS与BFS~
一、深度优先搜索
每次都是走到不能再走了才回到最近的一个交叉口。
***连通分量:***无向图中,如果两个顶点之间可以相互到达,(可以是通过一定的路径间接到达),那么这两个顶点就称为强连通。如果图G(V,E)的任意两个顶点都连通,则称图G为连通图;否则就是非连通图,并且称其中的极大连通子图为连通分量。
***强连通分量:***有向图中,如果两个顶点可以各自通过一条有向路径到达另一个顶点,就称为这两个顶点为强连通。如果图G(V,E)的任意两个顶点都强连通,就称图G为强连通图;否则就是非强连通图,且称其中的极大强连通子图为强连通分量。
下面的代码是DFS的伪代码~(邻接表和邻接矩阵都能套)
DFS(u){ //访问顶点u
vis[u] = true; //将u设置为已经访问
for(从u出发能到达的所有顶点) //枚举从u出发能到达的所有顶点
if vis[v] == false //如果v没有被访问
DFS(v);
}
DFSTrave(G){
for(G中的所有顶点u)
if vis[u] == false
DFS(u);
}
设置全局变量:
const int MAXV = 1000; //最大顶点数
const int INF = 1000000000; //设INF是一个很大的数
邻接矩阵模版
int n, G[MAXV][MAXV]; //n为顶点数
bool vis[MAXV] = {false}; //如果顶点i被访问,那么vis[i] = true
void DFS(int u, int depth){
vis[u] = true;
for(int v = 0; v < n; v ++){
if(G[u][v] != INF && vis[v] == false)
DFS(v, depth + 1);
}
}
void DFSTrave(){
for(int u = 0; u < n; u++){
if(vis[u] == false)
DFS(u, 1);
}
}
邻接表模版
vector<int> Adj[MAXV];
int n;
bool vis[MAXV] = {false};
void DFS(int u, int depth){
vis[u] = true;
for(int i = 0; i < n; i++){
int v = Adj[u][i];
if(vis[v] == false)
DFS(v, depth + 1);
}
}
void DFSTrave(){
for(int v = 0; v < n; v++){
if(vis[v] == false)
DFS(v, 1);
}
}
二、广度优先搜索
基本思想:建立一个队列,并且把初始顶点加入队列,此后每次都取出队首顶点进行访问,并且把该顶点出发可以达到的未曾加入过队列(而不是未访问)的顶点全部加入队列,直到队列为空。
以下为BFS伪代码~
BFS(u){ //遍历u所在的模块
queue q;
inq[u] = true; //设置u已经被加入过队列
while(q非空){
取出q的队首元素u进行访问;
for(从u出发可达的所有顶点v)
if(inq[v] == false){
将v入队;
inq[v] = true;
}
}
}
BFSTrave(G){
for(G的所有结点u)
if(inq[u] == false)
BFS(u);
}
邻接矩阵模版
int n, G[MAXV][MAXV];
bool inq[MAXV] = {false};
void BFS(int u){
queue<int> q;
q.push(u);
inq[u] = true;
while(!q.empty()){
int u = q.front();
q.pop();
for(int v = 0; v < n; v++){
//如果u的邻接点v未曾加入过队列
if(inq[v] == false && G[u][v] != INF){
q.push(v);
inq[v] = true;
}
}
}
}
void BFSTrave(){
for(int u = 0; u < n; u++){
if(inq[u] == false)
BFS(q);
}
}
邻接表模版
vector<int> Adj[MAXV];
int n;
bool inq[MAXV] = {false};
void BFS(int u){
queue<int> q;
q.push(u);
inq[u] = true;
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = 0; i < n; i++){
int v = Adj[u][i];
if(inq[v] == false){
q.push(v);
inq[v] = true;
}
}
}
}
void BFSTrave(){
for(int u = 0; u < n; u++){
if(inq[u] == false)
BFS(q);
}
}
与树的BFS类似,在给定BFS初始点的情况下,可能需要输出该连通块内所有其他顶点的层号,这时只需要修改少量内容即可达到要求(以邻接表为例,邻接矩阵也是同样的道理)
struct Node{
int v;
int layer;
};
vector<Node> Adj[N];
void BFS(int s){ //s是起始编号
queue<Node> q;
Node start;
start.layer = 0;
start.v = s;
q.push(start);
inq[start.v] = true;
while(!q.empty()){
Node topNode = q.front();
q.pop();
int u = topNode.v;
for(int i = 0; i < Adj[u].size(); i++){
Node next = Adj[u][i];
next.layer = topNode.layer + 1;
if(inq[next.v] == false){
q.push(next);
inq[next.v] = true;
}
}
}
}