图是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系。对象由顶点(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. 图的遍历算法:DFS、BFS

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

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

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

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

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

随机推荐

  1. [USACO11DEC]Umbrellas for Cows

    嘟嘟嘟 我dp真是太弱了,这么简单dp都不会. 令dp[i]表示前 i 头牛头被遮住了的最低成本.则dp[i] = min{dp[i], dp[j - 1] + c[a[i] - a[j] + 1]} ...

  2. 记一次关于SSM框架的使用错误

    今天遇到一个十分操蛋的问题,最后发现是因为忘记在对应的Service上加上@AutoWired. 难怪单元测试没问题,因为单元测试中用到的Service,其实现类通过DAO自动装配了.也就是在对应的s ...

  3. Selenium图片上传

    方式1: 如果是input类型的标签则可直接赋值 部分代码: driver.find_element_by_name("file").send_keys("E:\\tes ...

  4. javaWeb中怎么获取提交表单里面的值

    在javaWeb中如何获得html文件中的表单里面的值? <!DOCTYPE html> <html> <head> <meta charset=" ...

  5. 作为测试新手,web测试从何开始学起?

    我们先来弄清楚web测试的测试范围,通常web测试包含:功能测试.性能测试.浏览器兼容测试.安全测试以及用户界面测试等.那么,作为一个初级测试员或者实习测试员,最开始的能做的只能是功能测试和用户界面测 ...

  6. Jquery Mobile通过超链接跳转后CSS样式不起作用的解决办法

    Jquery Mobile中的超链接默认是采用AJAX跳转的,ajax获取到页面的内容之后,就直接替换当前页面的内容了,它只是单纯的获取页面的HTML代码,并不会再去下载引用的CSS代码和JS代码,因 ...

  7. 解决vue变量未渲染前代码显示问题

    在网络加载缓慢或者刷新的时候总会有那么一瞬间出现vue的模板代码,实在很影响美观,对于我这种有强迫症的人来说实在是忍无可忍,后来经过查找资料,终于发现了解决方法,可以使用vue现成的指令来解决这个问题 ...

  8. ubuntu安装flashplayer插件三步走

    1.去官网下载flash;2.解压3.复制.so文件到~/.mozilla/plugins/

  9. Elasticsearch 5.x安装

    node1 elasticsearch node2 elasticsearch node3 elasticsearch 前期准备 JDK1.8 修改/etc/security/limits.conf ...

  10. Jboot使用appassembler-maven-plugin插件生成启动脚本

    appassembler-maven-plugin介绍: 使用appassembler-maven-plugin插件可自动生成跨平台的启动脚本,可省去手工写脚本的麻烦,而且还可以生成jsw的后台运行程 ...