深度和广度优先搜索都是基于图(数据类型)的操作。
如果搜索是以接近起始状态的程序依次扩展状态的,叫广(宽)度优先搜索。
如果扩展是首先扩展新产生的状态,则叫深度优先搜索广度 优先搜索: 广度优先搜索是按照树的层次进行的搜索,如果此层没有搜索完成的情况下不会进行下一层的搜索。
广度 优先搜索: 广度优先搜索是按照树的层次进行的搜索,如果此层没有搜索完成的情况下不会进行下一层的搜索。
深度优先搜索: 深度优先搜索是按照树的深度进行搜索的,所以又叫纵向搜索,在每一层只扩展一个节点,直到为树的规定深度或叶子节点为止。这个便称为深度优先搜索。
深度优先搜索
深度优先搜索用栈(stack)来实现,整个过程可以想象成一个倒立的树形:
把根节点压入栈中。
每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的前驱。
找到所要找的元素时结束程序。
如果遍历整个树还没有找到,结束程序。
例如借助在对无向图进行深度遍历时去理解深搜:利用深度优先搜索实现深度优先遍历。深度优先遍历主要思想:首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;当不存在未被访问过的顶点时,回到上个顶点,继续试探访问别的顶点,直至所有顶点都被访问过。
(圈内为顶点编号,外为遍历序号)
常常用深搜去解决最短路径问题:
例题如下:小哼和小哈在n*m(n,m<=50)规格的迷宫中走散了,迷宫中有障碍物(用1表示),有空格(用0表示),现要求小哼以最快速度找到小哈,输出最少步数。前提:小哼不能走到给定的迷宫外部,遇到障碍物不可通行。
#include<stdio.h>
int n,m,p,q,min=99999999;
int a[51][51],book[51][51];
void dfs(int x,int y,int step){
int next[4][2]={{0,1}, //向右走
{1,0}, //向下走
{0,-1}, //向左走
{-1,0}}; //向上走
int tx,ty,k;
//判是否到达小哈位置
if(x==p&&y==q){
if(step<min) min=step; //更新最小值
return; //达到之后直接结束不再进行下列代码
}
//枚举四种走法
for(k=0;k<=3;k++){
//计算下一个点的坐标
tx=x+next[k][0];
ty=y+next[k][1];
//判断是否还处在迷宫中
if(tx<1||tx>n||ty<1||ty>m)
continue;
//判断在路上还是遇到了障碍物
if(a[tx][ty]==0&&book[tx][ty]==0){
book[tx][ty]=1; //标记已经走过的路
dfs(tx,ty,step+1); //尝试下一个点
book[tx][ty]=0; //尝试结束去除标记
}
}
return;
}
int main(void){
int i,j,startx,starty;
scanf("%d %d",&n,&m);
//读入迷宫相关数据,即空格与障碍物的坐标
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
//读入起始位置和终止位置
scanf("%d %d %d %d",&startx,&starty,&p,&q);
//从第一个顶点开始搜索
book[startx][starty]=1; //标记已经走过,防止重复经过
dfs(startx,starty,0);
printf("%d",min);
return 0;
}
运行结果:
广(宽)度优先搜索
广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:
把根节点放到队列的末尾。
每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
找到所要找的元素时结束程序。
如果遍历整个树还没有找到,结束程序。
例如借助在对无向图进行广度遍历时去理解广搜:利用广度优先搜索实现广度优先遍历。广度优先遍历主要思想:首先以一个未被访问过的顶点作为起始顶点,访问其所有的相邻的点,然后对每个相邻的顶点再访问它们所有的相邻未被访问过的点,直到所有点都被访问完,遍历结束。
针对上一题可以使用广度搜索去解决
#include<stdio.h>
int a[51][51],book[51][51];
struct node{
int x;
int y;
int s;
};
int main(void){
struct node que[2510];
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int head=1,tail=1;
int i,j,k,n,m,startx,starty,p,q,tx,ty,flag;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
scanf("%d %d %d %d",&startx,&starty,&p,&q);
que[tail].x=startx;
que[tail].y=starty;
que[tail].s=0;
tail+=1;
book[startx][starty]=1;
flag=0; //用来标记是否达到目的地,1已到达,0未到达
while(head<tail){
for(k=0;k<=3;k++){
tx=que[head].x+next[k][0];
ty=que[head].y+next[k][1];
if(tx<1||tx>n||ty<1||ty>n) continue;
if(a[tx][ty]==0&&book[tx][ty]==0){
book[tx][ty]=1;
que[tail].x=tx;
que[tail].y=ty;
que[tail].s=que[head].s+1;
tail+=1;
}
if(tx==p&&ty==q){
flag=1;
break;
}
}
if(flag==1)
break;
head+=1;
}
printf("%d",que[tail-1].s);
return 0;
}
搜索的要点:
(1)初始状态;
(2)重复产生新状态;
(3)检查新状态是否为目标,是结束,否转(2);