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详解的更多相关文章

  1. BFS和DFS详解以及java实现

    前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问的问题中几乎有一半的问题都可以用图的 ...

  2. BFS和DFS详解以及java实现(转载)

    作者:Leo-Yang 原文都先发布在作者个人博客:http://www.leoyang.net/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连 ...

  3. 图论-欧拉图-欧拉回路-Euler-Fluery-Hierholzer-逐步插入回路法-DFS详解-并查集

    欧拉图性质: 1.无向连通图G是欧拉图,当且仅当G不含奇数度结点(G的所有结点度数为偶数): 2.无向连通图G含有欧拉通路,当且仅当G有零个或两个奇数度的结点: 3.有向连通图D是欧拉图,当且仅当该图 ...

  4. Leetcode之广度优先搜索(BFS)专题-详解429. N叉树的层序遍历(N-ary Tree Level Order Traversal)

    Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree Level Order Traversal) 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右 ...

  5. 力扣:二叉树着色游戏(DFS详解)

    有两位极客玩家参与了一场「二叉树着色」的游戏.游戏中,给出二叉树的根节点 root,树上总共有 n 个节点,且 n 为奇数,其中每个节点上的值从 1 到 n 各不相同. 游戏从「一号」玩家开始(「一号 ...

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

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

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

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

  8. 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)

    参考网址:图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) - 51CTO.COM 深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath ...

  9. 深搜(DFS)广搜(BFS)详解

    图的深搜与广搜 一.介绍: p { margin-bottom: 0.25cm; direction: ltr; line-height: 120%; text-align: justify; orp ...

随机推荐

  1. 阅读INI档 - Delphi一片

    程序往往需要读一些用户设置值.如何完成这一过程? B/S程序一般使用XML档.和C/S程序使用INI档. 前篇<C#迁移之callXBFLibrary - 2(调用非托管DLL)>是C#读 ...

  2. spring4.2完整web项目(使用html视图解析器)

    完整配置springmvc4,最终视图选择的是html,非静态文件. 最近自己配置spring的时候,遇到很多问题,由于开发环境和版本的变化导致网友们给出的建议很多还是不能用的,可能还会有很多人会遇到 ...

  3. C++拷贝构造函数具体解释

    一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是非常easy的,比如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各 ...

  4. Android真正简单的教程-第十二枪(ViewFlipper实现滑动效果)

    直接看代码 1.MainActivity.java: package org.yayun.demo; import android.app.Activity; import android.os.Bu ...

  5. 解决VS 于 致命错误 RC1015: 无法打开包含文件 &#39;afxres.h&#39; 问题

    在试验VS2010当一个问题困扰了我,它是开放的c++项目达产后,rc的dialog入口.您不能拖动控制,让我疯狂... 而最有发言权的是在线Directions问题. .题明显不是这个问题. 于是我 ...

  6. hdu 4864 Task(贪婪啊)

    主题链接:pid=4864">http://acm.hdu.edu.cn/showproblem.php?pid=4864 Task Time Limit: 4000/2000 MS ...

  7. linux perm

    转自: http://www.linuxidc.com/Linux/2012-05/59693.htm 有修改 nd -perm,根据文件的权限来查找文件,有三种形式:find -perm modef ...

  8. 微信公众平台消息接口开发-封装weixin.class.php

    原文:微信公众平台消息接口开发-封装weixin.class.php 一.封装weixin.class.php 由于微信公众平台的通信使用的是特定格式的XML数据,每次接受和回复都要去做一大堆的数据处 ...

  9. MVC应用程序使用Wcf Service

    原文:MVC应用程序使用Wcf Service 前一篇Insus.NET有演示过MVC应用程序使用Web Service, 此篇Insus.NET想继续演示Service,不过是WCF Service ...

  10. VS2013调试的时候出现 “检测到在集成的托管管道模式下不适用的 ASP.NET 设置的解决方法”

    在web.config里面添加了下面一句,完美解决 <system.webServer> <validation validateIntegratedModeConfiguratio ...