本文兼参考自《算法导论》及《算法》。

  以前一直不能够理解深度优先搜索和广度优先搜索,总是很怕去碰它们,但经过阅读上边提到的两本书,豁然开朗,马上就能理解得更进一步。

  下文将会用到的一个无向图例子如下:

  

深度优先搜索

迷宫搜索

  在《算法》这本书中,作者写了很好的一个故事。这个故事让我马上理解了深度优先搜索的思想。

  如下图1-1所示,如何在这个迷宫中找到出路呢?方法见图1-2.

  

  图1-1 等价的迷宫模型

  探索迷宫而不迷路的一种古老办法(至少可以追溯到忒修斯和米诺陶的传说)叫做Tremaux搜索,如下图所示。要探索迷宫中的所有通道,我们需要:

  1)选择一条没有标记过的通道,在你走过的路上铺一条绳子;

  2)标记所有你第一次路过的路口和通道;

  3)当来到一个标记过的路口时,用绳子回退到上个路口;

  4)当回退到的路口已没有可走的通道时继续回退。

  绳子可以保证你总能找到一条出路,标记则能保证你不会两次经过同一条通道或同一个路口。

  

  图1-2 Tremaux探索

深度优先搜索

  《算法》作者给出的Java代码如下:

 public class DepthFirstSearch
{
private boolean[] marked;
private int count; public DepthFirstSearch(Graph G, int s)
{
marked = new boolean[G.V()];
dfs(G, s);
} private void dfs(Graph G, int v)
{
marked[v] = true;
count++;
for(int w : G.adj(v))
{
if(!marked[w])
{
dfs(G, w);
}
}
} public boolean marked(int w)
{
return marked[w];
} public int count()
{
return count;
}
}

DFS.java

  具体例子如下图1-3:

  

  图1-3 使用深度优先探索的轨迹,寻找所有和顶点0连通的顶点

寻找路径

  《算法》作者给出的Java代码如下:

 public class DepthFirstPaths
{
private boolean[] marked; // Has dfs() been called for this vertex?
private int[] edgeTo; // last vertex on known path to this vertex
private final int s; // source
public DepthFirstPaths(Graph G, int s)
{
marked = new boolean[G.V()];
edgeTo = new int[G.V()];
this.s = s;
dfs(G, s);
} private void dfs(Graph G, int v)
{
marked[v] = true;
for (int w : G.adj(v))
if (!marked[w])
{
edgeTo[w] = v;
dfs(G, w);
}
} public boolean hasPathTo(int v)
{
return marked[v];
} public Iterable<Integer> pathTo(int v)
{
if (!hasPathTo(v)) return null;
Stack<Integer> path = new Stack<Integer>();
for (int x = v; x != s; x = edgeTo[x])
path.push(x);
path.push(s);
return path;
}
}

DFS.java

  

  图1-4 pathTo(5)的计算轨迹

  

  图1-5 使用深度优先搜索的轨迹,寻找所有起点为0的路径

广度优先搜索

迷宫搜索

   深度优先搜索就好像是一个人在走迷宫,广度优先搜索则好像是一组人在一起朝各个方向走这座迷宫,每个人都有自己的绳子。当出现新的叉路时,可以假设一个探索者可以分裂为更多的人来搜索它们。当两个探索者相遇时,会合二为一(并继续使用先到达者的绳子)。如下图2-1:

  

  图2-1 广度优先的迷宫搜索

广度优先搜索

  《算法》作者给出的使用广度优先搜索查找图中的路径的Java代码如下:

 public class BreadthFirstPaths
{
private boolean[] marked; // Is a shortest path to this vertex known?
private int[] edgeTo; // last vertex on known path to this vertex
private final int s; // source public BreadthFirstPaths(Graph G, int s)
{
marked = new boolean[G.V()];
edgeTo = new int[G.V()];
this.s = s;
bfs(G, s);
} private void bfs(Graph G, int s)
{
Queue<Integer> queue = new Queue<Integer>();
marked[s] = true; // Mark the source
queue.enqueue(s); // and put it on the queue.
while (!q.isEmpty())
{
int v = queue.dequeue(); // Remove next vertex from the queue.
for (int w : G.adj(v))
if (!marked[w]) // For every unmarked adjacent vertex,
{
edgeTo[w] = v; // save last edge on a shortest path,
marked[w] = true; // mark it because path is known,
queue.enqueue(w); // and add it to the queue.
}
}
} public boolean hasPathTo(int v)
{
return marked[v];
} public Iterable<Integer> pathTo(int v)
// Same as for DFS.
}

BFS.java

  一个例子如下:

  

  图2-2 使用广度优先搜索寻找所有起点为0的路径的结果

  

  图2-3 使用广度优先搜索的轨迹,寻找所有起点为0的路径

  具体代码已经托管到Github.

"《算法导论》之‘图’":深度优先搜索、宽度优先搜索(无向图、有向图)的更多相关文章

  1. 挑战程序2.1.5 穷竭搜索>>宽度优先搜索

    先对比一下DFS和BFS         深度优先搜索DFS                                   宽度优先搜索BFS 明显可以看出搜索顺序不同. DFS是搜索单条路径到 ...

  2. 【算法入门】广度/宽度优先搜索(BFS)

    广度/宽度优先搜索(BFS) [算法入门] 1.前言 广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历策略.因为它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较 ...

  3. BFS算法的优化 双向宽度优先搜索

    双向宽度优先搜索 (Bidirectional BFS) 算法适用于如下的场景: 无向图 所有边的长度都为 1 或者长度都一样 同时给出了起点和终点 以上 3 个条件都满足的时候,可以使用双向宽度优先 ...

  4. 算法基础⑦搜索与图论--BFS(宽度优先搜索)

    宽度优先搜索(BFS) #include<cstdio> #include<cstring> #include<iostream> #include<algo ...

  5. 层层递进——宽度优先搜索(BFS)

    问题引入 我们接着上次“解救小哈”的问题继续探索,不过这次是用宽度优先搜索(BFS). 注:问题来源可以点击这里 http://www.cnblogs.com/OctoptusLian/p/74296 ...

  6. [宽度优先搜索] FZU-2150 Fire Game

    Fat brother and Maze are playing a kind of special (hentai) game on an N*M board (N rows, M columns) ...

  7. 【BFS宽度优先搜索】

    一.求所有顶点到s顶点的最小步数   //BFS宽度优先搜索 #include<iostream> using namespace std; #include<queue> # ...

  8. 宽度优先搜索--------迷宫的最短路径问题(dfs)

    宽度优先搜索运用了队列(queue)在unility头文件中 源代码 #include<iostream>#include<cstdio>#include<queue&g ...

  9. 搜索与图论②--宽度优先搜索(BFS)

    宽度优先搜索 例题一(献给阿尔吉侬的花束) 阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫. 今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔 ...

随机推荐

  1. WmS详解(一)之token到底是什么?基于Android7.0源码

    做Android有些年头了,Framework层三大核心View系统,WmS.AmS最近在研究中,这三大块,每一块都够写一个小册子来介绍,其中View系统的介绍,我之前有一个系列的博客(不过由于时间原 ...

  2. FFmpeg的H.264解码器源代码简单分析:环路滤波(Loop Filter)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  3. 学习Tensorflow,反卷积

    在深度学习网络结构中,各个层的类别可以分为这几种:卷积层,全连接层,relu层,pool层和反卷积层等.目前,在像素级估计和端对端学习问题中,全卷积网络展现了他的优势,里面有个很重要的层,将卷积后的f ...

  4. EBS中的采购单据状态及其控制

     李  颖 (济南钢铁股份有限公司 装备部,山东 济南 250101) 摘 要:介绍了Oracle Purchasing模块中采购单据的管理与控制,结合实例,分析了各状态下可采取的控制活动及控制活 ...

  5. 查看某一职责下对应的菜单&功能&请求

    查看菜单&功能 SELECT res.RESPONSIBILITY_NAME 职责名称, menu.MENU_NAME 菜单编码, menu.USER_MENU_NAME 菜单名称, func ...

  6. 【一天一道LeetCode】#219. Contains Duplicate II

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  7. Android开发学习之路--UI之初体验

    之前都是学习Activity,对于布局都没有做过学习,这里就简单学习下吧.下面看下Android Studio下有哪些控件: 这里分为Widgets,Text Fields,Containers,Da ...

  8. Android的ExpandableListView-android学习之旅(二十八)

    ExpandableListView简介 ExpandableListView是ListView的子类,用法和ListView类似,ExpandableListView可以创建几个类别,每个类别下面又 ...

  9. Android初级教程之内容提供者获取联系人信息

    内容提供折详细理论知识请参考之前的博文:http://blog.csdn.net/qq_32059827/article/details/51646513 这里新建了三个联系人信息,通过查看系统联系人 ...

  10. UNIX环境高级编程——线程同步之读写锁以及属性

    读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 互 ...