广度优先搜索(BFS)
广度优先搜索是最简单的一种图的搜索方式,也是许多图算法的原型,Dijkstra的单元最短路径和Prim的最小生成树算法等都使用了类似广度优先搜索的思想。其别名又叫BFS,属于一种盲目搜寻法,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止
思想: 从源点s出发,之后依次访问s的所有邻接点,再从这些邻接点出发依次遍历它们的邻接点(要保证先被访问的点的邻接点要在后被访问的邻接点之前)。直到图中所有的点都被遍历。
从下面的图中我们可以更直观的看出bfs遍历顺序
实现方式
1、将源点放入队列,并标记为已访问
2、取出队首元素
3、将其的邻接节点放入队列,并标记为已访问
4、重复2、3操作直到队列为空
经典例题 迷宫问题
给一个n*n的地图,0代表可行,1代表不可行,只能选择上下左右四个方向,从起点(1,1)到终点(n,n)的最路径长度是多少
5
01000
01010
00000
01010
00010
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f7f7f7f;
const int MAXN = 105;
int n;
char mp[MAXN][MAXN];
int vis[MAXN][MAXN], cnt[MAXN][MAXN];
int dix[10] = {0,1,0,-1};
int diy[10] = {-1,0,1,0};
struct node
{
int x,y;
};
void init()
{
memset(vis,0,sizeof(vis));
for(int i = 0; i <n; i ++)
for(int j = 0; j < n; j ++)
if(mp[i][j] == '1') cnt[i][j] = inf;
else cnt[i][j] = 0;
}
void bfs(int x, int y)
{
queue<node> que;
node pg;
pg.x = x;
pg.y = y;
que.push(pg);
vis[x][y] = 1;
while(!que.empty())
{
pg = que.front();
que.pop();
for(int i = 0; i < 4; i ++)
{
int nx = pg.x+dix[i];
int ny = pg.y+diy[i];
if(nx >= 0 && nx <n && ny >= 0 && ny < n && mp[nx][ny] =='0' && vis[nx][ny] == 0){
vis[nx][ny] = 1;
cnt[nx][ny] = cnt[pg.x][pg.y] + 1;
node pp;
pp.x = nx;
pp.y = ny;
que.push(pp);
}
}
}
if(cnt[n-1][n-1] == inf) printf("NO\n");
else printf("YES --> %d\n",cnt[n-1][n-1]);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i = 0; i <n; i ++)
scanf("%s",mp[i]);
init();
bfs(0,0);
}
}
深度优先搜索(DFS)
深度优先搜索,简称DFS,是一种简单的图的搜索方式,和BFS不同,DFS更加专注于一个分支一条路径的搜索,直到这一条路径无法继续走下去在回溯到上一个分叉口从其他路径搜索,直到整个图都被访问为止。
下面的图更能生动形象的表明
例题
给一个n*n的图,其中1代表湖,0,代表陆地,相邻的湖相连算一个湖,(不算对角的),问有多少湖?
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f7f7f7f;
const int MAXN = 105;
int n;
char mp[MAXN][MAXN];
int vis[MAXN][MAXN];
int dix[10] = {0,1,0,-1};
int diy[10] = {-1,0,1,0};
void init()
{
for(int i = 0; i < MAXN; i ++)
for(int j = 0; j < MAXN; j ++)
mp[i][j] = '0';
memset(vis,0,sizeof(vis));
}
void dfs(int x, int y)
{
vis[x][y] = 1;
for(int i = 0; i < 4; i ++)
{
int nx = x + dix[i];
int ny = y + diy[i];
if(mp[nx][ny] == '1' && vis[nx][ny]==0)
dfs(nx,ny);
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i = 1; i <= n; i ++)
scanf("%s",mp[i]+1);
int ans = 0;
for(int i = 1; i <= n; i ++)
for(int j = 0; j <= n; j ++)
if(mp[i][j] == '1' && vis[i][j] == 0){
dfs(i,j);
ans ++;
}
printf("%d\n",ans);
}
}
/*
5
11000
10001
01001
11000
00011
*/
思考:现在要实现二叉树的先序,中序,后序遍历改怎么做呢?
不了解的可以推荐大家看:https://blog.csdn.net/ThsRunningSnail/article/details/102781233
1、递归
void dfs(node T)
{
if(T == null) return; 出口
cout<<T->data<<endl;
dfs(T->lchild);
dfs(T->rchild);
}
void dfs(node T)
{
if(T == null) return; 出口
dfs(T->lchild);
cout<<T->data<<endl;
dfs(T->rchild);
}
void dfs(node T)
{
if(T == null) return; 出口
dfs(T->lchild);
dfs(T->rchild);
cout<<T->data<<endl;
}
非递归呢?
//先序
void PreOrder(Node T)
{
stack<Node> st;
while(T || !st.empty())
{
while(T)
{
cout << T->data <<endl;
st.push(T);
T = T->lchild;
}
if( !st.empty())
{
T = st.top();
st.pop();
T = T->rchild;
}
}
}
//上述代码均提供思路,并未实际测试
中序和后序大家可以自己思考推导。