"《算法导论》之‘图’":深度优先搜索、宽度优先搜索(无向图、有向图)
本文兼参考自《算法导论》及《算法》。
以前一直不能够理解深度优先搜索和广度优先搜索,总是很怕去碰它们,但经过阅读上边提到的两本书,豁然开朗,马上就能理解得更进一步。
下文将会用到的一个无向图例子如下:

深度优先搜索
迷宫搜索
在《算法》这本书中,作者写了很好的一个故事。这个故事让我马上理解了深度优先搜索的思想。
如下图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.
"《算法导论》之‘图’":深度优先搜索、宽度优先搜索(无向图、有向图)的更多相关文章
- 挑战程序2.1.5 穷竭搜索>>宽度优先搜索
先对比一下DFS和BFS 深度优先搜索DFS 宽度优先搜索BFS 明显可以看出搜索顺序不同. DFS是搜索单条路径到 ...
- 【算法入门】广度/宽度优先搜索(BFS)
广度/宽度优先搜索(BFS) [算法入门] 1.前言 广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历策略.因为它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较 ...
- BFS算法的优化 双向宽度优先搜索
双向宽度优先搜索 (Bidirectional BFS) 算法适用于如下的场景: 无向图 所有边的长度都为 1 或者长度都一样 同时给出了起点和终点 以上 3 个条件都满足的时候,可以使用双向宽度优先 ...
- 算法基础⑦搜索与图论--BFS(宽度优先搜索)
宽度优先搜索(BFS) #include<cstdio> #include<cstring> #include<iostream> #include<algo ...
- 层层递进——宽度优先搜索(BFS)
问题引入 我们接着上次“解救小哈”的问题继续探索,不过这次是用宽度优先搜索(BFS). 注:问题来源可以点击这里 http://www.cnblogs.com/OctoptusLian/p/74296 ...
- [宽度优先搜索] 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) ...
- 【BFS宽度优先搜索】
一.求所有顶点到s顶点的最小步数 //BFS宽度优先搜索 #include<iostream> using namespace std; #include<queue> # ...
- 宽度优先搜索--------迷宫的最短路径问题(dfs)
宽度优先搜索运用了队列(queue)在unility头文件中 源代码 #include<iostream>#include<cstdio>#include<queue&g ...
- 搜索与图论②--宽度优先搜索(BFS)
宽度优先搜索 例题一(献给阿尔吉侬的花束) 阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫. 今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔 ...
随机推荐
- How Do I Declare A Block in Objective-C? [备忘]
How Do I Declare A Block in Objective-C? As a local variable: returnType (^blockName)(parameterTypes ...
- not in 前面/后面存在null值时的处理
表声明 order_header表中有ship_method列: ship_method_map表中ship_method为主键列. 需求 找出order_header表中所有ship_method不 ...
- [openwrt] uci 的shell和lua接口
uci是openwrt上配置操作的接口,不管是自动化的shell脚本,还是使用luci来二次开发配置界面,都会用到这部分知识. uci提供了lua, shell, c接口,这里主要用到了前两种 she ...
- ExpandableListView简单应用及listview模拟ExpandableListView
首先我们还是来看一些案例,还是拿搜狐新闻客户端,因为我天天上下班没事爱看这个东东,上班又没时间看新闻,上下班路途之余浏览下新闻打发时间嘛. 看这个效果挺棒吧,其实实现起来也不难,我 ...
- Cocos2D iOS之旅:如何写一个敲地鼠游戏(六):放置地鼠
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 使用maven将项目打成jar包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
- java虚拟机工具入门
jps 能显示现在都有那些java程序运行 C:\Users\Administrator>jps 16964 DeadLockJstack 9172 PULSEI~1.JAR 19392 Jps ...
- Android的ImageView介绍-android学习之旅(二十二)
ImageView简介 imageView继承于View,主要用于显示图片,凡是Drawable对象都可以用它显示. ImageView直接派生了ImageButton和ZoomButton等组件. ...
- 成员函数的const到底修饰的是谁
demo <pre name="code" class="cpp">class Test { public: const void OpVar(in ...
- Android初级教程理论知识(第三章测试&数据存储&界面展现)
首先介绍单元测试,我在javaweb部分有详细介绍单元测试框架的一篇文章. 可以先看在javaweb中的单元测试详解篇http://blog.csdn.net/qq_32059827/article/ ...