当前课程知识点:数据结构(上) > 第六章 图 > (d)深度优先搜索 > 06D-5 有向图
相对于无向图
有向图的深度优先搜索要更为复杂
所涉及的情况也会更多
我们不妨来看这样一个实例
首先确认这是一幅有向图
在这个图中
我们将每一个顶点
都绘制成长方形
顶点的标识居中
在它的左右空白处 我们将分别
记录下它在遍历过程中
所获得的dTime和fTime两个时间标签
因此如果起点是A的话
它将在dTime等于1 也就是第一秒的时刻
被发现
同样 我们将它转为大写
并且将这个边框加粗 以示区别
以下从顶点 a 出发
经过一条有向边
我们可以在第二秒发现
并访问顶点B
同样地 我们将它变为大写
并加粗边框 以示区别
而此时处于DISCOVERED状态的顶点a
也需要以双线边框
与其它顶点相区别
以下从顶点b出发
又可以经过一条有向边
在第三秒发现并且处理顶点c
虽然从表面看顶点 c
存在若干条邻边
但是因为这里是有向图
实际上从c并没有发出
任何有效的边
因此在顶点c处
我们不得不做一次回溯
同样地 逆向经过刚才那条树边
回到顶点B
不要忘了 在此前我们需要为这个
已经访问结束的顶点c
记下它的fTime时间标签
也就是3+1等于4
再以下
同样地 顶点b在接过控制权之后
也会发现它的所有的邻居都已扫描
并且处理完毕
因此会继续沿着它所对应的那条树边
逆向地抵达它的父亲节点 也就是A
同样 顶点b访问结束的时刻
是4+1 也就是5
在顶点A再次地获得了控制权之后
它会继续刚才没有做完的事情
也就是继续扫描
它的其它邻接顶点
比如这里的顶点c 请注意
这是我们第一次遇到的一个情况
它的特征是我们立足当前的顶点
会发现它有一个邻居已经处于最终的
VISITED状态
已经访问完毕了
你应该还记得我们所设计的算法
在这种情况下 我们应该进而
分两种子情况来进行讨论
而区分的准则
就是dTime 时间标签
具体来说 要看当前节点A
与它的邻居节点c
谁的时间标签更小
或者等价地 谁更早被发现
如果像这种情况所示的那样
我们可以看到 1小于3
这就说明 顶点A相对于它的邻居c
是更早被发现的
因此根据算法的规则
我们应该将它们之间的那条有向边
归类为FORWARD
什么意思呢? 向前边
我想通过这个例子 你应该能够
很好地理解为什么叫向前边
没错 它的意思是说这条边
是由遍历树中的祖先节点向前
指向它的后代
所以称作FORWARD EDGE
是再形象和合适不过的了
再以下 顶点A还有一个邻居f
处于UNDISCOVERED的状态
这也就是为什么在接下来的第六秒
顶点F将接过控制权
此后呢 它将在第7秒将控制权交给
它的下一个邻居 也就是顶点G
现在我们立足于顶点G
也同样要去环顾四周
逐一地考察它的邻居们
我们可以看到 第一个邻居是顶点a
请注意 此时应该属于算法的第二种情况
这个邻居当前处于第二种状态
也就是DISCOVERED
根据算法的规则
我们应该将它们之间的
这条有向边
归类为BACKWARD
后向边或者叫回边
我们也该来体会一下为什么叫回边
你应该能看出来
其实它等效于在遍历树中
我们试图从一个后代
去回连到它的祖先
所以称之为BACKWARD
是再形象不过的了
同样地 一旦出现BACKWARD边
也就同时意味着我们发现了
至少一条回路
这样一个性质的严格证明
大家可以参考我们的教材
以及习题解析
好 再接下来 我们依然立足于
当前的顶点G
考察它的下一个邻居 也就是顶点c
当然 因为我们的状态变化是不可逆的
所以c自然依然处于
最终的VISITED状态
也就是说 我们又再次地遇到了
算法的第三种情况
同样 我们需要比较它们的
dTime时间标签
从而进一步地明确
此时到底是属于
两种子情况中的哪一种
不难看出 7要大于3
而不像此前1小于3
所以此时应该是处于
第三种情况中的
后一种子情况
你应该还记得
按照我们所设计的算法规则
此时应该将从当前顶点通往它邻居的
那条连边 归入CROSS一类
也就是跨边 跨越边
为什么称作是跨越边呢?
我们不难看出 在整个遍历树中
这两个顶点之间
并没有任何的祖先或后代的
直系血缘关系
如果要形象比喻的话
它们只不过是姑表亲
这样一类连接于姑表亲顶点之间的边
首先不应该称作是FORWARD边
其次也不应该称作是BACKWARD边
而称作跨越边
则是再形象和合适不过的了
至此 g的所有邻居
都已扫描并且处理完毕
因此对它的访问也应随即终止
所以它会在第八秒
记录下它的fTime时间标签
并且逆向地回退到它的父节点
也就是F
而此时的F顶点呢 所有的邻居
也都处理完毕
因此它依然需要回溯
同样 在回溯之前
也需要记下它的fTime时间标签
也就是8+1=9
最终的控制权
又再次地回到顶点A的手中
此时的顶点a
所有的邻接顶点也都扫描
并且处理完毕
所以也轮到它结束自己的遍历过程
它的fTime时间标签
应该是9再加1
也就是10
综观整个过程
我们总共用了10秒
遍历完了由这五个顶点所构成的
一个子图
更确切地讲 它们构成了
在这个图中 从顶点a出发
可以达到的区域
也称作可达区域
那么图中的其余部分呢?
比如说这里的顶点d以及e呢?
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验