图是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系。对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示。 图可以分为有向图和无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。 在图的基本算法中,最初需要接触的就是图的遍历算法,根据访问节点的顺序,可分为广度优先搜索(BFS)和深度优先搜索(DFS)。


广度优先搜索(BFS) 广度优先搜索在进一步遍历图中顶点之前,先访问当前顶点的所有邻接结点。 a .首先选择一个顶点作为起始结点,并将其染成灰色,其余结点为白色。 b. 将起始结点放入队列中。 c. 从队列首部选出一个顶点,并找出所有与之邻接的结点,将找到的邻接结点放入队列尾部,将已访问过结点涂成黑色,没访问过的结点是白色。如果顶点的颜色是灰色,表示已经发现并且放入了队列,如果顶点的颜色是白色,表示还没有发现 d. 按照同样的方法处理队列中的下一个结点。 基本就是出队的顶点变成黑色,在队列里的是灰色,还没入队的是白色。 用一副图来表达这个流程如下:

1.初始状态,从顶点1开始,队列={1}

2.访问1的邻接顶点,1出队变黑,2,3入队,队列={2,3,}

3.访问2的邻接结点,2出队,4入队,队列={3,4}

4.访问3的邻接结点,3出队,队列={4}

5.访问4的邻接结点,4出队,队列={ 空}

从顶点1开始进行广度优先搜索:

  1. 初始状态,从顶点1开始,队列={1}
  2. 访问1的邻接顶点,1出队变黑,2,3入队,队列={2,3,}
  3. 访问2的邻接结点,2出队,4入队,队列={3,4}
  4. 访问3的邻接结点,3出队,队列={4}
  5. 访问4的邻接结点,4出队,队列={ 空} 结点5对于1来说不可达。 上面的图可以通过如下邻接矩阵表示:
     int maze[][] = {
    { , , , , },
    { , , , , },
    { , , , , },
    { , , , , },
    { , , , , }
    };

    BFS核心代码如下:

     #include <iostream>
    #include <queue>
    #define N 5
    using namespace std;
    int maze[N][N] = {
    { , , , , },
    { , , , , },
    { , , , , },
    { , , , , },
    { , , , , }
    };
    int visited[N + ] = { , };
    void BFS(int start)
    {
    queue<int> Q;
    Q.push(start);
    visited[start] = ;
    while (!Q.empty())
    {
    int front = Q.front();
    cout << front << " ";
    Q.pop();
    for (int i = ; i <= N; i++)
    {
    if (!visited[i] && maze[front - ][i - ] == )
    {
    visited[i] = ;
    Q.push(i);
    }
    }
    }
    }
    int main()
    {
    for (int i = ; i <= N; i++)
    {
    if (visited[i] == )
    continue;
    BFS(i);
    }
    return ;
    }

    深度优先搜索(DFS) 深度优先搜索在搜索过程中访问某个顶点后,需要递归地访问此顶点的所有未访问过的相邻顶点。 初始条件下所有节点为白色,选择一个作为起始顶点,按照如下步骤遍历: a. 选择起始顶点涂成灰色,表示还未访问 b. 从该顶点的邻接顶点中选择一个,继续这个过程(即再寻找邻接结点的邻接结点),一直深入下去,直到一个顶点没有邻接结点了,涂黑它,表示访问过了 c. 回溯到这个涂黑顶点的上一层顶点,再找这个上一层顶点的其余邻接结点,继续如上操作,如果所有邻接结点往下都访问过了,就把自己涂黑,再回溯到更上一层。 d. 上一层继续做如上操作,知道所有顶点都访问过。 用图可以更清楚的表达这个过程:

    1.初始状态,从顶点1开始

    2.依次访问过顶点1,2,3后,终止于顶点3

    3.从顶点3回溯到顶点2,继续访问顶点5,并且终止于顶点5

    4.从顶点5回溯到顶点2,并且终止于顶点2

    5.从顶点2回溯到顶点1,并终止于顶点1

    6.从顶点4开始访问,并终止于顶点4

    从顶点1开始做深度搜索:

    1. 初始状态,从顶点1开始
    2. 依次访问过顶点1,2,3后,终止于顶点3
    3. 从顶点3回溯到顶点2,继续访问顶点5,并且终止于顶点5
    4. 从顶点5回溯到顶点2,并且终止于顶点2
    5. 从顶点2回溯到顶点1,并终止于顶点1
    6. 从顶点4开始访问,并终止于顶点4

      上面的图可以通过如下邻接矩阵表示:

       int maze[][] = {
      { , , , , },
      { , , , , },
      { , , , , },
      { , , , , },
      { , , , , }
      };

      DFS核心代码如下(递归实现):

       #include <iostream>
      #define N 5
      using namespace std;
      int maze[N][N] = {
      { , , , , },
      { , , , , },
      { , , , , },
      { , , , , },
      { , , , , }
      };
      int visited[N + ] = { , };
      void DFS(int start)
      {
      visited[start] = ;
      for (int i = ; i <= N; i++)
      {
      if (!visited[i] && maze[start - ][i - ] == )
      DFS(i);
      }
      cout << start << " ";
      }
      int main()
      {
      for (int i = ; i <= N; i++)
      {
      if (visited[i] == )
      continue;
      DFS(i);
      }
      return ;
      }

      非递归实现如下,借助一个栈:

       #include <iostream>
      #include <stack>
      #define N 5
      using namespace std;
      int maze[N][N] = {
      { , , , , },
      { , , , , },
      { , , , , },
      { , , , , },
      { , , , , }
      };
      int visited[N + ] = { , };
      void DFS(int start)
      {
      stack<int> s;
      s.push(start);
      visited[start] = ;
      bool is_push = false;
      while (!s.empty())
      {
      is_push = false;
      int v = s.top();
      for (int i = ; i <= N; i++)
      {
      if (maze[v - ][i - ] == && !visited[i])
      {
      visited[i] = ;
      s.push(i);
      is_push = true;
      break;
      }
      }
      if (!is_push)
      {
      cout << v << " ";
      s.pop();
      } }
      }
      int main()
      {
      for (int i = ; i <= N; i++)
      {
      if (visited[i] == )
      continue;
      DFS(i);
      }
      return ;
      }

      有的DFS是先访问读取到的结点,等回溯时就不再输出该结点,也是可以的。算法和我上面的区别就是输出点的时机不同,思想还是一样的。DFS在环监测和拓扑排序中都有不错的应用。

感谢卡巴拉的树提供的文章,本文来自于http://www.jianshu.com/p/70952b51f0c8

图的基本算法(BFS和DFS)(转载)的更多相关文章

  1. 图的基本算法(BFS和DFS)

    图是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系.对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示. 图可以分为有向图和无向图,一般用G=(V,E)来表示图. ...

  2. 聊聊算法——BFS和DFS

    如果面试字节跳动和腾讯,上来就是先撕算法,阿里就是会突然给你电话,而且不太在意是周末还是深夜, 别问我怎么知道的,想确认的可以亲自去试试.说到算法,直接力扣hard三百题也是可以的,但似乎会比较伤脑, ...

  3. PAT Advanced 1034 Head of a Gang (30) [图的遍历,BFS,DFS,并查集]

    题目 One way that the police finds the head of a gang is to check people's phone calls. If there is a ...

  4. 图的遍历(bfs 和dfs)

    BFS的思想: 从一个图的某一个顶点V0出发,首先访问和V0相邻的且未被访问过的顶点V1.V2.……Vn,然后依次访问与V1.V2……Vn相邻且未被访问的顶点.如此继续,找到所要找的顶点或者遍历完整个 ...

  5. PAT Advanced 1076 Forwards on Weibo (30) [图的遍历,BFS,DFS]

    题目 Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and ...

  6. 图 邻接表 邻接矩阵 BFS生成树 DFS生成树

  7. 【数据结构与算法】自己动手实现图的BFS和DFS(附完整源码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/19617187 图的存储结构 本文的重点在于图的深度优先搜索(DFS)和广度优先搜索(BFS ...

  8. 图的遍历算法:DFS、BFS

    在图的基本算法中,最初需要接触的就是图的遍历算法,根据访问节点的顺序,可分为深度优先搜索(DFS)和广度优先搜索(BFS). DFS(深度优先搜索)算法 Depth-First-Search 深度优先 ...

  9. 图的基本算法(BFS和DFS)

    图是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系.对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示. 图可以分为有向图和无向图,一般用G=(V,E)来表示图. ...

随机推荐

  1. css :target

    花了半小时在找如果完成:target的问题 需求:点击<a href="#Main">Main</a>时,会触发:target 效果 结果在网络上没有找到, ...

  2. 使用LVS+keepalived实现mysql负载均衡的实践和总结

    前言 经过一段时间的积累,数据库的架构就需要根据项目不断的进行变化. 从单台数据库,到了两台数据库的主从,再到读写分离,再到双主,现在进一步需要更多的数据库服务器去支撑更加可怕的访问量. 那么经过那么 ...

  3. 《C#语言和数据库技术基础》单词必备

    <C#语言和数据库技术基础> 第一章1..NET Framework   框架2.sharp            尖锐,强烈的3.application      应用程序4.devel ...

  4. github学习(一)

    初识github篇. 一.什么是github:       GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub.       g ...

  5. Extjs中创建Tree菜单【一】

    此篇treepanel的描写是很简单,没有太大的难度,在学习时,可以先熟悉tree的一些配置信息.属性.方法和事件. 然后先写一个简单的例子,慢慢了解从中如何实现的,然后在慢慢的深入了解,实现一些复杂 ...

  6. SQL Server-聚焦NOLOCK、UPDLOCK、HOLDLOCK、READPAST你弄懂多少?(三十四)

    前言 时间流逝比较快,博主也在快马加鞭学习SQL Server,下班回来再晚也不忘记更新下博客,时间挤挤总会有的,现在的努力求的是未来所谓的安稳,每学一门为的是深度而不是广度,求的是知识自成体系而不是 ...

  7. JNI之C初探

    JNI是Java Native Interface的缩写,从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI一开始是为了本地已编译语言,尤其 ...

  8. maven配置文件setting.xml字段注释

    maven的配置文件为settings.xml,在下面路径中可以找到这个文件,分别为: $M2_HOME/conf/settings.xml:全局设置,在maven的安装目录下: ${user.hom ...

  9. java基础:数组的复制

  10. MyEclipse下安装MyBatis Generator代码反向生成工具

    一.离线方式: 在http://mybatis.googlecode.com/svn/sub-projects/generator/trunk/eclipse/UpdateSite/下载 featur ...