图论——深度优先搜索,广度优先搜索,拓扑排序

这是两种常用的搜索方式,但是应用不同。

广度优先搜索,在与搜索一个节点到另一个节点的最短距离。
深得优先搜索则侧重图中节点(假设节点代表某些事件)的发生顺序。

广度优先搜索

广度优先搜索,类似与将图组织称一种树的形式(但是可能不是一棵树,应为有环形)。
然后分层进行遍历,一层遍历玩以后遍历下一层。

使用队列作为辅助。遍历一层节点(也就是所有分支)的时候将下一层节点都添加到队列,这样,一层结束以后,下一层的节点都在队列中。然后从该队列中取元素,进行处理,处理的同时,将本层的节点的下一层(也就是相关联节点再次添加到队列)。
在遍历的时候需要一个memo,用来记录该节点的遍历状态
第一种memo:已遍历,正在遍历,未遍历。
原因在于,当节点处于正在遍历的状态时,如果节点的兄弟节点相互连通,那么第二个兄弟节点将会遍历两次,所以在第一次遇到一个节点的时候,标记为正在遍历。当再次遇到带节点(兄弟节点要添加该节点进队列),节点为正在遍历,因此跳过添加。
只添加未遍历的节点进队列。

第二种memo:已遍历,为遍历
这种memo方法,在添加如队列之前就将其标记为已遍历。这样就避免了循环添加。

最短路径

广度有限搜索是可以的到最短路径的,其的到最短路径的方式在于:
每个节点存储一个值d表示该节点到起点的距离。同时存放一个本节点的父节点p
在遍历的过程中,如果本节点为未遍历,那么:本节点的d等于上一个节点的d+1,本节点的p等于上一个节点。
该赋值过程发生在添加到队列之前,某点已经被添加到队列,那么不应该在赋值。

当遍历存在分支,在某个点的时候两个分支回合,第一次遍历的时候将回合点添加到队列,而本条分支就是会合点距离起始点的最短路径。而下一次遍历到回合点的分支,一定大于等于本次的。
因为广度优先遍历按层遍历。

最短路径就保存在这些p中,从结束点,依次递归或者迭代的去访问节点的p就可以到达起始点。

所以,可以看出,广度优先搜索其按层搜索的特征决定了可以用于最短路径的搜索

深度优先搜索

深度优先搜索其搜索过程,是,优先搜索分支的每一条分支。到达最深处返回,再去搜索另一条分支。
这类似与一个栈。

同样也需要上面两种形式的memo,来防止节点的循环添加。

在遍历一个节点的时候,处理完该节点以后,将其分支全部压入栈中。再从栈中取出一个元素,处理该元素结束以后再将该元素的分支压入此栈。。。。。。如此循环,可以发现,栈基本上是在增长的(当分支只有一个时,不变化),直到到达了分支的末端,栈开始减少。

深度优先搜索中的d(距离)并没有什么用,因为其已经不再代表最短距离,而是取决于同一个节点不同分支的遍历顺序。

拓扑排序

因为深度优先搜索的搜索特性,其可以用来表示节点(将节点想象成事件)的发生先后顺序,而遍历的结果是其中一种可能的顺序(存在环形)。

比如,我们从起始点开始遍历图,可以想为,穿衣的顺序。
起始点有两条分支:穿上衣,穿下衣,穿鞋袜。
那么深度优先搜索会尽可能深的遍历其中一条分支,比如穿上衣:内衣->衬衣->外套。
在衬衣和外套之间可能存在戴领带,带臂章最终又在穿外套点回合,因此是一个环形。
内衣->衬衣->领带->臂章->外套。
因为环形的存在因此给出一种顺序。

因此如果每个点保存一个:该点开始处理时间,该点处理结束的时间。
那么在这两个时间之间,是该节点的分支的处理时间。
{a{b…b}{c…c}a}
bb,cc 中间是其节点分支。

最短路径

http://blog.csdn.net/qq_32353771/article/details/52820176

使用最深优先搜索求最短路径,需要在遍历完一个点的时候,再将这个点该为未遍历。
但是低效,如果一个节点的子节点相互连通,那么一定会被重复遍历!

强连通分量

一个有向图中,如果任意两点之间可到达,那么该图是一个强连通图
在一个非强连通图中,某个子图可以是强连通图,那么最大的强连通子图就是强连通分量

    原文作者:Myth52125
    原文地址: https://www.jianshu.com/p/1e557582d825
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞