【0】README

0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 如何对无向图进行深度优先搜索 的idea 并用源代码加以实现;

0.2) 本文还引入了 背向边(定义见下文描述),并用源代码找出了给定图的在 DFS过程中 产生的背向边, 但是要注意 背向边不是深度优先搜索树的边, 该树是由 对给定图进行DFS生成的;

0.3) 通过打印 parent (可以看做是 深度优先搜索树的边), 我们可以大致知晓 深度优先搜索树的大致框架,并结合背向边,我们就可以将 DFS 的全部流程看清楚了;

0.4)背向边的添加操作是比较重要的: 因为后面的DFS应用到 ”双连通性“、”有向图“以及”查找强分支“ 都要用到 背向边;


【1】DFS应用与无向图相关

1.1)DFS应用与测试无向图是否连通:无向图是连通的, 当且仅当从任一节点开始的深度优先搜索访问到每一个节点。因为这项测试应用起来非常容易, 所以我们将假设我们处理的图都是连通的。如果它们不连通,那么我们可以找出所有的连通分支并将我们的算法依次应用于每个分支;

1.2)看个荔枝:



对上图的深度优先搜索步骤(steps)进行分析(Analysis)(这只是深度优先搜索的一种可能情况)

  • A1)建立深度优先生成树的步骤

    • step1)任取一个 顶点A;
    • step2)将 顶点A 标记为已访问过, 并递归调用 DFS(B);
    • step3)将 顶点B 标记为已访问过, 并递归调用 DFS(C);
    • step4)将 顶点C 标记为已访问过, 并递归调用 DFS(D);
    • step5)将 顶点D 标记为已访问过, 由于 顶点A,顶点C 均被访问过,所以return;
    • step6)递归return到 顶点C, 并递归调用DFS(E);
    • step7)将 顶点E 标记为已访问过, 由于没有未被访问过的顶点,所以算法over;
  • A2)对边的处理(引入背向边的定义): 如果当我们处理(v, w)时 发现w是未被标记的, 或当我们处理(w, v)时发现v是未标记的,那么我们就用树的一条边表示它; 如果当我们处理 (v, w)时发现w 是已被标记的, 并且当我们处理(w, v)时发现v 也是已标记的, 那么我们就画一条虚线, 并称之为背向边,表示这条边实际上不是树的一部分;

1.3)树将模拟我们执行的遍历顺序, 如右上图所示。只使用树的边对该树的先序编号告诉我们这些顶点被标记的顺序。 如果图不是连通的, 那么处理所有节点(和边)都需要多次调用DFS, 每次都生成一颗树,整个集合就是 深度优先生成森林(depth-first spanning forest)如右上图所示;

1.4)深度优先搜索无向图的递归步骤解析如下:

1.5)看个荔枝——对给定图在DFS过程中添加背向边(backside)的过程


【2】source code + printing results

2.0)code specification:

我个人以为代码中的干货,一个当然是 DFS 的递归过程,另一个则是 添加背向边的代码,它的if 条件语句如下:

if(visited[adjVertex]) // judge whether the adjVertes was visited before
{
if(vertexIndex[vertex] > vertexIndex[adjVertex] && parent[vertex] != adjVertex)
{
parent[adjVertex] = vertex; // building back side, attention of condition of building back side above // just for printing effect
for(i = 0; i < depth; i++)
printf(" ");
printf("vertex[%c]->vertex[%c] (backside) \n", flag[vertex], flag[adjVertex]);
}
}
  • s1)对以上代码的分析: 当顶点vertex 的邻接顶点被访问过时,如果该邻接顶点 晚于 当前顶点vertex 访问, 且 该邻接顶点不是当前顶点vertex的 parent的话,那么就符合添加 背向边的条件了;(这里有点打脑筋,慢慢理解)
  • s2)我们讲为什么要添加背向边? 因为我们的初衷是要让 深度优先搜索树的各个顶点的可达程度 和 给定的初始图的顶点可达情况类似或相同;你要想, 如果存在 (v1,v2) ,那必然有(v2,v1), 所以如果v1 是v2的parent,此时如果你又添加了 v2到 v1的背向边,那岂不是没有意义;我们再想, 如果 v1先于v2被访问, 你又添加了 v1到v2的背向边,那岂不是还是没有意义,请对照到上述代码中的 if 条件语句以便理解 为什么那样去添加背向边

2.1)download source code: https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter9/p241_dfs_undirected_graph

2.2)source code at a glance:(for complete code , please click the given link above)

#include "dfs.h"

extern char flag[];

void dfs(Vertex vertex, int depth)
{
int i;
AdjTable temp;
Vertex adjVertex; //printf("\n\t visited[%c] = 1 ", flag[vertex]);
visited[vertex] = 1; // update visited status of vertex
vertexIndex[vertex] = counter++; // number the vertex with counter
temp = adj[vertex]; while(temp->next)
{
adjVertex = temp->next->vertex;
if(visited[adjVertex]) // judge whether the adjVertes was visited before
{
if(vertexIndex[vertex] > vertexIndex[adjVertex] && parent[vertex] != adjVertex)
{
parent[adjVertex] = vertex; // building back side, attention of condition of building back side above // just for printing effect
for(i = 0; i < depth; i++)
printf(" ");
printf("vertex[%c]->vertex[%c] (backside) \n", flag[vertex], flag[adjVertex]);
}
} else
{
parent[adjVertex] = vertex; // just for printing effect
for(i = 0; i < depth; i++)
printf(" ");
printf("vertex[%c]->vertex[%c] (building edge)\n", flag[vertex], flag[adjVertex]);
dfs(adjVertex, depth+1);
} temp = temp->next;
}
}

2.3)printing results:

对无向图的深度优先搜索(DFS)的更多相关文章

  1. 深度优先搜索DFS和广度优先搜索BFS简单解析(新手向)

    深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每个点仅被访问一次,这个过程就是图的遍历.图的遍历常用的有深度优先搜索和广度优先搜索,这两者对于有向图和无向图 ...

  2. 深度优先搜索DFS和广度优先搜索BFS简单解析

    转自:https://www.cnblogs.com/FZfangzheng/p/8529132.html 深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每 ...

  3. 利用广度优先搜索(BFS)与深度优先搜索(DFS)实现岛屿个数的问题(java)

    需要说明一点,要成功运行本贴代码,需要重新复制我第一篇随笔<简单的循环队列>代码(版本有更新). 进入今天的主题. 今天这篇文章主要探讨广度优先搜索(BFS)结合队列和深度优先搜索(DFS ...

  4. (转)广度优先搜索BFS和深度优先搜索DFS

    1. 广度优先搜索介绍 广度优先搜索算法(Breadth First Search),又称为"宽度优先搜索"或"横向优先搜索",简称BFS. 它的思想是:从图中 ...

  5. 【算法入门】深度优先搜索(DFS)

    深度优先搜索(DFS) [算法入门] 1.前言深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解 ...

  6. 深度优先搜索 DFS 学习笔记

    深度优先搜索 学习笔记 引入 深度优先搜索 DFS 是图论中最基础,最重要的算法之一.DFS 是一种盲目搜寻法,也就是在每个点 \(u\) 上,任选一条边 DFS,直到回溯到 \(u\) 时才选择别的 ...

  7. 广度优先(bfs)和深度优先搜索(dfs)的应用实例

    广度优先搜索应用举例:计算网络跳数 图结构在解决许多网络相关的问题时直到了重要的作用. 比如,用来确定在互联网中从一个结点到另一个结点(一个网络到其他网络的网关)的最佳路径.一种建模方法是采用无向图, ...

  8. 用深度优先搜索(DFS)解决多数图论问题

    前言 本文大概是作者对图论大部分内容的分析和总结吧,\(\text{OI}\)和语文能力有限,且部分说明和推导可能有错误和不足,希望能指出. 创作本文是为了提供彼此学习交流的机会,也算是作者在忙碌的中 ...

  9. 深度优先搜索(DFS)

    [算法入门] 郭志伟@SYSU:raphealguo(at)qq.com 2012/05/12 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一 ...

随机推荐

  1. 代理模式(Proxy)--动态代理(JDK)

    在是上一篇博客中实现了静态代理. 在上篇的结尾提到了一个问题: 思考:如果我们下需要对火车,自行车实现相同的代理,我们又该如何实现呢? 这篇博客就来解决这个问题: 解决这类问题需要用到动态代理技术,实 ...

  2. ThinkPHP的自动验证常用的正则

    ThinkPHP的自动验证常用的正则   ThinkPHP的自动验证机制是为了进行表单数据验证,验证可以支持function. callback.confirm.equal.unique和regex, ...

  3. RestAPI的实现

    转自:http://blog.csdn.net/yanical/article/details/7856670 Rest的作者认为计算机发展到现在,最大的成就不是企业应用,而是web,是漫漫无边的互联 ...

  4. java内存溢出分析工具:jmap使用实战

    在一次解决系统tomcat老是内存撑到头,然后崩溃的问题时,使用到了jmap. 1 使用命令 在环境是linux+jdk1.5以上,这个工具是自带的,路径在JDK_HOME/bin/下 jmap -h ...

  5. Swift入门(一)——基本的语法

    近期開始学习swift.把学习的过程和总结整理成一个系列.方便日后回想总结. 基本的语法 基础语法 swift中每一行结束后不须要加分号.多个语句在同一行内须要用分好隔开 //表示凝视.或者用/* - ...

  6. nginx rewrite不支持if 嵌套也不支持逻辑或和逻辑并

    如题,apache的rewrite是支持或者的,用个OR就可以,如果不加OR,多个RewriteCond 罗列累加就是并且的意思.然后nginx的rewrite就没有这么好了.那么如何去实现这样复杂的 ...

  7. 一分钟sed入门

    [转载于58同城沈剑] 1.简介 sed是一种行编辑器,它一次处理一行内容. 2.sed调用方式 sed [options] 'command' file(s) sed [options] -f sc ...

  8. 编译spark源码及塔建源码阅读环境

    编译spark源码及塔建源码阅读环境 (一),编译spark源码 1,更换maven的下载镜像: <mirrors> <!-- 阿里云仓库 --> <mirror> ...

  9. java-selenium(二)富文本编辑框的处理

    首先先看一下什么是富文本编辑框 HTML源码 思路:首先先进入到iframe中,再用js写,最后切出iframe 如果想要换行可以在换行的地方加上<br> 如果添加的文本中包含单引号.双引 ...

  10. 2016.3.16__HTML5新特性__第八天

    HTML 5 + CSS 3 假设您认为这篇文章还不错,能够去H5专题介绍中查看很多其它相关文章. 今日代码非常冗杂,所以非常多内容直接摘自网上,假设造成您的不适.请留言告知. 非常感谢. 输入标签, ...