DFS(Depth First Search,深度优先搜索)和BFS(Breadth First Search,广度优先搜索)是两种典型的搜索算法。下面通过一个实例来比较一下深度优先搜索和广度优先搜索的搜索过程。

【例1】马的行走路径

设有一个n*m的棋盘(2<=n<=50,2<=m<=50),在棋盘上任一点有一个中国象棋马,如图1(a)所示。马行走的规则为:(1)马走日字;(2)马只能向右走,即如图1(b)所示的4种走法。

编写一个程序,输入n和m,找出一条马从棋盘左下角(1,1)到右上角(n,m)的路径。例如:输入n=4、m=4时,输出路径 (1,1)->(2,3)->(4,4)。这一路经如图1(c)所示。若不存在路径,则输出"No!"

(1)编程思路。

将棋盘的横坐标规定为i,纵坐标规定为j,对于一个n×m的棋盘,i的值从1到n,j的值从1到m。棋盘上的任意点都可以用坐标(i,j)表示。

马有四种移动方向,每种移动方法用偏移值来表示,将这些偏移值分别保存在数组dx和dy中,可定义数组int dx[4]={1,1,2,2}和int dy[4]={-2,2,-1,1}。

定义数组int visit[51][51]标记某位置马儿是否已走过,初始时visit数组的所有元素值均为0,visit[i][j]=0表示坐标(i,j)处马儿未走过。同时为了后面输出路径方便,在标记visit[i][j]的值时,可以将其设置为其前一个位置的信息,例如visit[i][j] = x*100+y,它表示马儿由坐标(x,y)走到坐标(i,j)处。

(2)采用深度优先搜索编写的源程序。

#include <iostream>

using namespace std;

#define N 51

struct Node

{

int x;

int y;

};

int main()

{

int n,m;

int dx[4]={1,1,2,2};

int dy[4]={-2,2,-1,1};

int visit[N][N]={0};

Node s[N*N],cur,next;   // s为栈

int  top,i,x,y,t;         // top为栈顶指针

cin>>n>>m;

top=-1;               // 栈S初始化

cur.x=1;  cur.y=1;

visit[1][1]=-1;          // 点(1,1)为出发点,无前驱结点

s[++top]=cur;           // 初始结点入栈;

bool flag= false;        // 置搜索成功标志flag为假

while(top>=0 && !flag)   // 栈不为空

{

cur=s[top--];        // 栈顶元素出栈

if (cur.x==n && cur.y==m)

{

flag=true;

x=n;  y=m;

while (visit[x][y]!=-1)

{

cout<<"("<<x<<","<<y<<") <-- ";

t=visit[x][y];

x=t/100;

y=t%100;

}

cout<<"(1,1)"<<endl;

break;

}

for (i=0;i<4;i++)

{

x=cur.x+dx[i];  y=cur.y+dy[i];

if(x >=1 && x<=n && y>=0 && y<=m && visit[x][y]==0)

{

visit[x][y] = (cur.x)*100+cur.y;  // 映射保存前驱结点信息

next.x=x;  next.y=y;          // 由cur扩展出新结点next

s[++top]=next;               // next结点入栈

}

}

}

if (!flag)

cout<<"No path!"<<endl;

return 0;

}

为理解深度优先搜索的结点访问顺序,可以在上面源程序中的出栈语句后加上一条语句

cout<<"("<<cur.x<<","<<cur.y<<") -- ";  输出结点的出栈访问顺序。

(3)DFS的搜索过程。

以输入5,5为例,用树形结构表示马可能走的所有过程(如下图),求从起点到终点的路径,实际上就是从根结点开始搜索这棵树。

马从(1,1)开始,按深度优先搜索法,扩展出两个结点(2,3)和(3,2)依次入栈,之后(3,2)出栈,即走一步到达(3,2),判断是否到达终点,若没有,则继续往前走,扩展出结点(4,4)、(5,1)、(5,3)依次入栈,再走一步到达(5,3),没有到达终点,继续往前走,(5,3)的下一步所走的位置不在棋盘上,则另选一条路径再走;(5,1)出栈,即走到(5,1);…,直到到达(5,5),搜索过程结束。

以输入5,5为例,输出的深度优先访问顺序为:

(1,1) -- (3,2) -- (5,3) -- (5,1) -- (4,4) -- (5,2) -- (2,3) -- (4,2) -- (5,4) -- (3,5) -- (4,3) -- (5,5)。

(4)采用广度优先搜索编写的源程序。

#include <iostream>

using namespace std;

#define N 51

struct Node

{

int x;

int y;

};

int main()

{

int n,m;

int dx[4]={1,1,2,2};

int dy[4]={-2,2,-1,1};

int visit[N][N]={0};

Node q[N*N],cur,next;     // q为队列

int  front,rear,i,x,y,t;        // front为队头指针,rear队尾指针

cin>>n>>m;

front=rear=0;                // 队列q初始化

cur.x=1;  cur.y=1;

visit[1][1]=-1;               // 点(1,1)为出发点,无前驱结点

q[rear++]=cur;            // 初始结点入队

bool flag= false;          // 置搜索成功标志flag为假

cout<<"结点访问顺序为:";

while(rear!=front && !flag)   // 队列不为空

{

cur=q[front++];        // 队头元素出队

cout<<"("<<cur.x<<","<<cur.y<<") -- ";

if (cur.x==n && cur.y==m)

{

flag=true;

x=n;  y=m;

cout<<endl;

cout<<"行走路径为:";

while (visit[x][y]!=-1)

{

cout<<"("<<x<<","<<y<<") <-- ";

t=visit[x][y];

x=t/100;

y=t%100;

}

cout<<"(1,1)"<<endl;

break;

}

for (i=0;i<4;i++)

{

x=cur.x+dx[i];  y=cur.y+dy[i];

if(x >=1 && x<=n && y>=1 && y<=m && visit[x][y]==0)

{

visit[x][y] = (cur.x)*100+cur.y;  // 映射保存前驱结点信息

next.x=x;  next.y=y;  // 由cur扩展出新结点next

q[rear++]=next;       // next结点入栈

}

}

}

if (!flag)

cout<<"No path!"<<endl;

return 0;

}

(5)BFS的搜索过程。

结合上面的搜索图,广度优先搜索采用自上而下,从左到右的顺序搜素结点。因此,结点访问顺序为:(1,1) -- (2,3) -- (3,2) -- (3,1) -- (3,5) -- (4,2) -- (4,4) -- (5,1) -- (5,3) -- (4,3) -- (5,2) -- (5,4) -- (5,5)。

DFS和BFS的比较的更多相关文章

  1. Clone Graph leetcode java(DFS and BFS 基础)

    题目: Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. ...

  2. 数据结构(12) -- 图的邻接矩阵的DFS和BFS

    //////////////////////////////////////////////////////// //图的邻接矩阵的DFS和BFS ////////////////////////// ...

  3. 数据结构(11) -- 邻接表存储图的DFS和BFS

    /////////////////////////////////////////////////////////////// //图的邻接表表示法以及DFS和BFS //////////////// ...

  4. 在DFS和BFS中一般情况可以不用vis[][]数组标记

    开始学dfs 与bfs 时一直喜欢用vis[][]来标记有没有访问过, 现在我觉得没有必要用vis[][]标记了 看代码 用'#'表示墙,'.'表示道路 if(所有情况都满足){ map[i][j]= ...

  5. 图论中DFS与BFS的区别、用法、详解…

    DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...

  6. 图论中DFS与BFS的区别、用法、详解?

    DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...

  7. 数据结构基础(21) --DFS与BFS

    DFS 从图中某个顶点V0 出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到(使用堆栈). //使用邻接矩阵存储的无向图的深度 ...

  8. dfs和bfs的区别

    详见转载博客:https://www.cnblogs.com/wzl19981116/p/9397203.html 1.dfs(深度优先搜索)是两个搜索中先理解并使用的,其实就是暴力把所有的路径都搜索 ...

  9. 邻接矩阵实现图的存储,DFS,BFS遍历

    图的遍历一般由两者方式:深度优先搜索(DFS),广度优先搜索(BFS),深度优先就是先访问完最深层次的数据元素,而BFS其实就是层次遍历,每一层每一层的遍历. 1.深度优先搜索(DFS) 我一贯习惯有 ...

  10. 判断图连通的三种方法——dfs,bfs,并查集

    Description 如果无向图G每对顶点v和w都有从v到w的路径,那么称无向图G是连通的.现在给定一张无向图,判断它是否是连通的. Input 第一行有2个整数n和m(0 < n,m < ...

随机推荐

  1. Linux 下非 root 用户安装 theano(配置 GPU)

    非 root 用户,安装 Python 第三方的包,尤其像 theano,存在大量的依赖项,存在的主要问题,是安装各个包时的权限问题.所幸,存在这样一个集成工具,叫 anaconda,其已经内置了许多 ...

  2. C# WPF报表打印

    前天我的一个同学由于打印报表而苦恼,所以就介绍了一下WPF的打印报表,希望能帮助到大家. 展示报表 1. 首先新建项“报表”,选定项目,右击,点击“添加”->“新建项”->“报表”

  3. [视频]mac系统下虚拟机parallels安装ubuntu 14.04视频教程

    此文是http://www.mr-wu.cn/install-ubuntu-14-04-on-parallels-for-mac/这篇博文的补充,为整个ubuntu 14.04安装过程的视频录像. m ...

  4. java_Mac安装多个JDK版本并设置环境变量

    JDK6.JDK7.JDK8三个版本的汇总地址:https://pan.baidu.com/s/1pKSYv8Z 安装 JDK6安装 JDK6下载地址 见网盘 安装完毕后确认版本 JavaForOSX ...

  5. ListView、TreeView和DataGrid。

    原文:ListView.TreeView和DataGrid. 1.ListView. ListView继承自简单的没有特色的ListBox,并使用View属性进行扩展.增加了对基于列显示的支持,并增加 ...

  6. 数据在数组中存储的顺序:小端 OR 大端模式 详解

    大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放: 小端模式,是指数据的高 ...

  7. .Net Core中使用NodeJs加解密DES,MD5,AES,REA

    鉴于使用.net core我们的加解密也同时迁移到了跨平台上,我使用的是NodeJs加解密的.废话不多说了,还是来干活吧. 1.创建Node项目 2.添加package.json {  "n ...

  8. seajs教程(一):基本用法

    介绍 SeaJS 是一个适用于 Web 浏览器端的模块加载器.使用 SeaJS,可以更好地组织 JavaScript 代码. Sea.js 遵循 CMD 规范,模块化JS代码.依赖的自动加载.配置的简 ...

  9. 【全面解禁!真正的Expression Blend实战开发技巧】序章

    原文:[全面解禁!真正的Expression Blend实战开发技巧]序章 从silverlight2开始我也和大家一样一直在跟随微软的脚步,从sl2~sl4一步一步过来,总结了不少心得体会.由于各种 ...

  10. Java中的逆变与协变 专题

    结论先行: PECS总结: 要从泛型类取数据时,用extends: 协变 要往泛型类写数据时,用super: 逆变 既要取又要写,就不用通配符(即extends与super都不用) 不变 List&l ...