BFS和DFS详解
BFS和DFS详解以及java实现
前言
图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇《Get that job at Google!》文章中说到面试官问的问题中几乎有一半的问题都可以用图的方法去解决。由此也可以看出图确实适用范围确实很广。
图的表示
闲话不多说,首先要介绍的就是图的表示,图最常用的两种表示方法是邻接表和邻接矩阵。顾名思义,这两种办法分别用表和矩阵的方式描述图中各顶点之间的联系

下图展示了两种表示上面这个图的方法

BFS
本文将着重介绍遍历图的两种最常用的方法,分别为广度优先遍历和深度优先遍历,后面会具体介绍为什么这么命名。首先来看广度优先遍历BFS(Breadth First Search),其主要思想是从起始点开始,将其邻近的所有顶点都加到一个队列(FIFO)中去,然后标记下这些顶点离起始顶点的距离为1.最后将起始顶点标记为已访问,今后就不会再访问。然后再从队列中取出最先进队的顶点A,也取出其周边邻近节点,加入队列末尾,将这些顶点的距离相对A再加1,最后离开这个顶点A。依次下去,直到队列为空为止。从上面描述的过程我们知道每个顶点被访问的次数最多一次(已访问的节点不会再访问),而对于连通图来说,每个顶点都会被访问。加上每个顶点的邻接链表都会被遍历,因此BFS的时间复杂度是Θ(V+E),其中V是顶点个数,E是边数,也就是所有邻接表中的元素个数。为了更好的说明这个过程,下图列出了对一个图的BFS的过程


private static void bfs(HashMap<Character, LinkedList<Character>> graph,HashMap<Character, Integer> dist,char start)
{
Queue<Character> q=new LinkedList<>();
q.add(start);//将s作为起始顶点加入队列
dist.put(start, 0);
int i=0;
while(!q.isEmpty())
{
char top=q.poll();//取出队首元素
i++;
System.out.println("The "+i+"th element:"+top+" Distance from s is:"+dist.get(top));
int d=dist.get(top)+1;//得出其周边还未被访问的节点的距离
for (Character c : graph.get(top)) {
if(!dist.containsKey(c))//如果dist中还没有该元素说明还没有被访问
{
dist.put(c, d);
q.add(c);
}
}
}
}

运行结果:

从运行结果我们也可以看到,w r作为距离为1的顶点先被访问,x t v其后,最后访问y u。上面的代码使用了一个小的trick,用dist这个hash表来记录每个顶点离s的距离,如果dist中没有这个元素则说明还未被访问,这时将距离写入dist中。BFS访问得到的每个节点与起始顶点的距离是起始顶点到达该顶点的最短距离。从感性认识上来说,BFS向外扩散的方式得到的距离就是最短距离。详细的证明过程请参考CLRS上的相应章节
DFS
DFS(Depth First Search)深度优先搜索是从起始顶点开始,递归访问其所有邻近节点,比如A节点是其第一个邻近节点,而B节点又是A的一个邻近节点,则DFS访问A节点后再访问B节点,如果B节点有未访问的邻近节点的话将继续访问其邻近节点,否则继续访问A的未访问邻近节点,当所有从A节点出去的路径都访问完之后,继续递归访问除A以外未被访问的邻近节点。因为是递归过程,所以我们用过程图看一下也许会更直观一些。

如下是DFS的代码及运行结果

private static void dfs(HashMap<Character , LinkedList<Character>> graph,HashMap<Character, Boolean> visited)
{
visit(graph, visited, 'u');//为了和图中的顺序一样,我认为控制了DFS先访问u节点
visit(graph,visited,'w');
}
private static void visit(HashMap<Character , LinkedList<Character>> graph,HashMap<Character, Boolean> visited,char start)
{
if(!visited.containsKey(start))
{
count++;
System.out.println("The time into element "+start+":"+count);//记录进入该节点的时间
visited.put(start, true);
for (char c : graph.get(start))
{
if(!visited.containsKey(c))
{
visit(graph,visited,c);//递归访问其邻近节点
}
}
count++;
System.out.println("The time out element "+start+":"+count);//记录离开该节点的时间
}
}

运行结果:

我们通过一个全局变量count记录了进入每个节点和离开每个节点的时间,我们也可以看到进出元素的时间和过程图中的访问过程是一样的。
总结
总的来说,BFS多用于寻找最短路径的问题,DFS多用于快速发现底部节点。以后若有时间再贴几道相关的题目上来。
BFS和DFS详解的更多相关文章
- BFS和DFS详解以及java实现
前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问的问题中几乎有一半的问题都可以用图的 ...
- BFS和DFS详解以及java实现(转载)
作者:Leo-Yang 原文都先发布在作者个人博客:http://www.leoyang.net/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连 ...
- 图论-欧拉图-欧拉回路-Euler-Fluery-Hierholzer-逐步插入回路法-DFS详解-并查集
欧拉图性质: 1.无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数): 2.无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点: 3.有向连通图D是欧拉图,当且仅当该图 ...
- Leetcode之广度优先搜索(BFS)专题-详解429. N叉树的层序遍历(N-ary Tree Level Order Traversal)
Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree Level Order Traversal) 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右 ...
- 力扣:二叉树着色游戏(DFS详解)
有两位极客玩家参与了一场「二叉树着色」的游戏.游戏中,给出二叉树的根节点 root,树上总共有 n 个节点,且 n 为奇数,其中每个节点上的值从 1 到 n 各不相同. 游戏从「一号」玩家开始(「一号 ...
- 图论中DFS与BFS的区别、用法、详解…
DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...
- 图论中DFS与BFS的区别、用法、详解?
DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...
- 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)
参考网址:图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) - 51CTO.COM 深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath ...
- 深搜(DFS)广搜(BFS)详解
图的深搜与广搜 一.介绍: p { margin-bottom: 0.25cm; direction: ltr; line-height: 120%; text-align: justify; orp ...
随机推荐
- sgu 194 被动散热器具有最大流量的上限和下限(最大流量模板dinic加上优化)
模板类型的题详细參考国家集训队论文:http://wenku.baidu.com/view/0f3b691c59eef8c75fbfb35c.html 參考博客:http://blog.csdn.ne ...
- 【MySQL案件】mysql登录-S失败
1.1.1. mysql登录mysql时间,-S参数失效 [环境的叙述性说明] mysql5.5.14 [问题叙述性说明] 配置多个实例 实例1 实例2 datadir /home/mysql_330 ...
- hdu3689(kmp+dp)
题意:问随机生成一个长度为m(m<=1000)长度的字符串,出现某个子串s的概率是多少. 解法:dp+kmp优化.ans[i][j]表示i长度,走到了s的j位置的概率,当然这是在i之前没有出现s ...
- [Phonegap+Sencha Touch] 移动开发34 gem安装compass,不编译scss,怎么办?
很多人已经发现,今天,该命令 "gem install compass" 安装compass,正在使用 "compass compile" 编scss的时间将报 ...
- Swift # 柯里化函数
前言 此次文章,讲述的是Swift的一个新特性(柯里化函数),可能很多iOS开发人员是第一次听这个词汇,包括我自己也是,自己也用了几天时间才总结出来,希望能帮助到各位咯,个人感觉偏向有开发经验的码友, ...
- javascript继承—继承的实现原理(1)
原文:javascript继承-继承的实现原理(1) 打算针对js的继承写一系列文章,详细的分析js里继承原理,实现方式,各种继承方式的优缺点,以及最优继承方案,还有多继承的问题等…. 面向对象的编程 ...
- .Net 2.0实例学习:WebBrowser页面与WinForm交互技巧
原文:.Net 2.0实例学习:WebBrowser页面与WinForm交互技巧 最近看到博客园入门教学文章比较流行,自己最近又偷懒比较多,没啥心得,不妨写一篇没啥深度的入门文章吧. 话说有了WebB ...
- SQL字符串处理函数
字符串函数对二进制数据.字符串和表达式运行不同的运算.此类函数作用于CHAR.VARCHAR. BINARY. 和VARBINARY 数据类型以及能够隐式转换为CHAR 或VARCHAR的数据类型. ...
- HTTP 错误500.19 -Internal Server Error
原文:HTTP 错误500.19 -Internal Server Error HTTP 错误500.19 -Internal Server Error 错误代码 0x80070021 评论1 字号: ...
- 文字超出DIV后,隐藏文字并显示...
<html> <head> <style type="text/css"> #cs{width:100px;height:50px;line-h ...