对于BFS,其实相比之下比DFS更加简单一些。
如果说DFS是为了走出一条最深的路径,那么BFS就是更像是为了层层扩张来达到访问所有节点的目的,例如树中的层序遍历,也可以认为是一种BFS;
BFS更像是逐层扩散的过程,所以BFS不需要回溯,所以也就不需要递归,更多的实现方式是利用队列,来进行层序输出;之前刷题中,也利用过队列进行过BFS的逐层访问,来记录树的层数,其实现在想想,利用DFS更直观一点;
其实BFS自己接触比较多的在图论和树论里,这里补充两个问题来辅助一下BFS的了解;
这道题是书上给出的经典实例,目的是找出矩阵中的各个不连通的块;
对于这个问题,就可以很好的采用BFS来解决;
代码如下所示:
#include<cstdio>
#include<stdlib.h>
using namespace std;
const int maxn=100;
struct node{
int x,y;
}Node;
int n,m;
int matrix[maxn][maxn];
bool inq[maxn][maxn]={false};
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};
//注意这里是为了进行BFS访问时候,可以生成上下左右四个方向的坐标
bool judge(int x,int y){
//判定条件
if(x>=n||x<0||y>=m||y<0)
return false;
if(matrix[x][y]=0||inq[x]==true)
return false;
return true;
}
void BFS(int x,int y){
queue<node>Q;
Node.x=x,Node.y=y;
Q.push(Node);
while(!Q.empty()){
node top=Q.front();
Q.pop();
for(int i=0;i<4;i++){
int newX=top.x+X[i];
int newY=top.y+Y[i];
if(judge(newX,newY)){
//当可以进行访问
Node.x=newX;
Node.y=newY;
Q.push(Node);
inq[newX][newY]=true;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int x=0;x<n;x++){
for(int y=0;y<m;y++){
scanf("%d",&matrix[x][y]);
}
}
int ans=0;
for(int x=0;x<n;x++){
//挨个进行访问从而遍历出不同的块
for(int y=0;y<m;y++){
if(matrix[x][y]==1&&inq[x][y]=false){
ans++;
BFS(x,y);
}
}
}
printf("%d\n",ans);
return 0;
}
这里要注意一个点,之前自己写BFS的时候完全没想过:
上述的代码最后一行并不是标志访问没有,而是有没有入队,这是一个很重要的差别;
之前如果只是判断是否访问,是先执行入队在进行判别,这样会造成很多的出队入队操作,造成不必要的时间浪费;所以如果判断入队没有,会减少不必要的入队出队操作,降低时间复杂度;
还有,要注意STL中queue的一个特性,入队的都只是副本,对队列中的元素进行改变并不影响初始值,所以一般queue最好存储下标索引,避免更改造成的不便;