参考资料:《算法笔记》
使用工具:队列queue
思想:
通过反复取出队首顶点,将该顶点能到达的未曾加入队列的顶点入队,直到队列为空时遍历结束,
具体实现:
如果图是连通图,那么一次BFS就能遍历完成所有顶点:
bfs(u){ //遍历u所在的连通块
queue q;
将u入队;
inq[u] = true; //设置q已经加入过队列
while(q非空){
取出队首元素进行访问;
for(从u出发能到达的所有顶点v){
if(未加入过队列){
将v入队;
标记v加入过队列;
}
}
}
}
BFStrave(G){ //遍历图G
for(G的所有顶点u){
if(inq[u] == false) //u未加入过队列
BFS(u);
}
}
邻接矩阵实现:
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 ++){
if(g[u][v] != INF && inq[v] == false){
q.push(v);
inq[v] = true;
}
}
}
}
void BFStravel(){ //遍历图g
for(int i = 0; i < n; i ++ ){
if(inq[i] == false){
bfs(i);
}
}
}
邻接表实现:
邻接表里adj[u][i]是u已经能到达的顶点,所以不需要判断是否能到达;
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 < adj[u].size(); i ++){
int v = adj[u][i];
if(inq[v] == false){ //肯定能到达,不需要判断
q.push(v);
inq[v] = true;
}
}
}
}
void BFStravel(){ //遍历图g
for(int i = 0; i < n; i ++ ){
if(inq[i] == false){
bfs(i);
}
}
}
补充情况:在给定bfs的初始点的情况下,可能要输出该连通块内其他顶点的层号,这时候需要定义结构体,在其中放顶点的编号和层号:
struct node{
int v, layer; //编号 层号
}
vector<node> adj[maxn];
如果当前层号是L,那么它所出边的终点的层号都为L+1;
此时的邻接表实现:
void bfs(int s){ //s为起点编号
queue<node> q;
node start; //新建起点,编号为s 层数为0
start.v = s;
start.layer = 0;
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; //层数+1
if(inq[next.v] == false){ //肯定能到达,不需要判断
q.push(next);
inq[next.v] = true;
}
}
}
}