图的拓扑排序定义:
给定一幅有向图, 对图中各顶点排序, 使得对于图中的任意有向边 v − > w v->w v−>w, 均满足节点 v v v出现在节点 w w w之前.
我们可以很容易证明, 存在环路的有向图无法进行排序.
假设当前有向图中存在某条环路 v 1 − > v 2 − > . . . − > v k − > v 1 v_1->v_2->...->v_k->v_1 v1−>v2−>...−>vk−>v1, 根据拓扑排序要求,排序后节点应满足 v 1 v_1 v1应出现在 v 2 v_2 v2之前, v 2 v_2 v2应出现在 v k v_k vk之前,… v k − 1 v_{k-1} vk−1应出现在 v k v_k vk之前, 因此 v 1 v_1 v1应出现在 v k v_k vk之前. 而由于存在边 v k − > v 1 v_k->v_1 vk−>v1, 因此 v k v_k vk应出现在 v 1 v_1 v1前, 无法同时满足.因此不存在拓扑排序结果.
以下简述一种用于有向无环图拓扑排序算法并对之进行证明.
对图中所有节点进行深度优先搜索, 保存节点的逆后序排列即得到节点的拓扑排序.
何为逆后序?
后序是指在每次递归调用结束后保存当前节点, 逆序是指按照先进后出的顺序保存节点, 通常 借助栈结构实现.因此逆后序即指在每次节点深度优先搜索调用完成后, 将节点压入栈中.
证明:对图中各节点进行深度优先搜索得到的逆后序即为有向无环图的拓扑排序.
证:对于图中任意边
v
−
>
w
v->w
v−>w, 在调用dfs(v)
对节点
v
v
v进行深度优先搜索时, 必有如下三种情形之一:
dfs(w)
已经被调用过且已经返回.dfs(w)
还未被调用, 因此 v − > w v->w v−>w有向边可能直接或间接调用 d f s ( w ) dfs(w) dfs(w), 并在dfs(v)
之前返回.dfs(w)
已被调用还未返回. 若当前 d f s ( w ) dfs(w) dfs(w)调用未返回, 则表明当前函数调用栈上存在由 w w w到 v v v的调用链, 因此图上必然存在由 w w w到 v v v的路径.由于图中存在 v − > w v->w v−>w, 因此图中存在环, 这在有向无环图中是不可能存在的.
对于情形1, 2, 由于dfs(w)
均在dfs(v)
之前返回, 因此逆后序列中节点 v v v必然在节点 w w w之前, 符合拓扑排序要求.
因此, 对图中各顶点进行深度优先搜索得到的逆后序列即为有向无环图的拓扑排序. 注意该方法中只需遍历所有节点即可.节点的遍历顺序可任意.