最近接触了一下拓朴排序,手痒写了下代码,给自己找了点麻烦,dfs特地没有用递归做;
关于拓朴排序的原理有很多人写得很好了,请参考以下文章:
https://blog.youkuaiyun.com/qinzhaokun/article/details/48541117
https://blog.youkuaiyun.com/yafeichang/article/details/53893120
https://www.cnblogs.com/xiangkejin/p/6965124.html
https://www.cnblogs.com/xiangkejin/p/6965124.html
第一篇非常好,截取其中一段:
对于基于DFS的算法,加入结果集的条件是:顶点的出度为0。这个条件和Kahn算法中入度为0的顶点集合似乎有着异曲同工之妙,这两种算法的思想犹如一枚硬币的两面,看似矛盾,实则不然。一个是从入度的角度来构造结果集,另一个则是从出度的角度来构造。
#!/user/bin/env python
# -*- coding:utf8 -*-
__author__ = 'zky@msn.cn'
''' 基于邻接矩阵的有向图 '''
class Digraph(object):
def __init__(self, V, E):
self._V = V
self._E = E
self.num_vertexes = len(V)
self.num_edges = len(E)
# init adjacency matrix
self._AM = []
for i in range(self.num_vertexes):
self._AM.append([0 for i in range(self.num_vertexes)])
for e in self._E:
v_h, v_t = e
self._AM[v_h][v_t] = 1
def dfs(self, v, order="post", result=None):
if order == "pre":
return self._dfs_pre_order(v, result)
else:
return self._dfs_post_order(v, result)
''' 非递归前序深度遍历 '''
def _dfs_pre_order(self, v, result=None):
if not v in self._V:
print "not found %s" % v
return None
result_pre = []
if result is not None:
result_pre = result
if v in result_pre:
return result_pre
finished = False
stack_pre = []
stack_pre.append(v)
while not finished:
v = stack_pre.pop()
result_pre.append(v)
i = self._V.index(v)
for j in range(self.num_vertexes)[::-1]:
if self._AM[i][j]:
v = self._V[j]
if v not in result_pre and v not in stack_pre: # not checked yet
stack_pre.append(v)
if 0 == len(stack_pre):
finished = True
return result_pre
''' 非递归后序深度遍历 '''
'''
使用两个栈,分别保存节点路径和待处理节点
'''
def _dfs_post_order(self, v, result=None):
if not v in self._V:
print "not found %s" % v
return None
result_post = []
if result is not None:
result_post = result
if v in result_post:
return result_post
finished = False
stack_checking = []
stack_waiting = []
stack_waiting.append(v)
while not finished:
v = stack_waiting.pop()
while len(stack_checking) and v == stack_checking[-1]:
result_post.append(v)
stack_checking.pop()
if 0 == len(stack_waiting):
finished = True
assert 0 == len(stack_checking)
else:
v = stack_waiting.pop()
if v not in stack_checking and v not in result_post: # not checked yet
stack_checking.append(v)
stack_waiting.append(v) # push it back to make a sentinel
i = self._V.index(v)
for j in range(self.num_vertexes)[::-1]:
if self._AM[i][j]:
v = self._V[j]
stack_waiting.append(v)
if 0 == len(stack_checking) and 0 == len(stack_waiting):
finished = True
return result_post
''' 非递归广度遍历 '''
def bfs(self, v):
if not v in self._V:
print "not found %s" % v
return False
result = []
checking = 0
finished = False
result.append(v)
while not finished:
i = self._V.index(v)
for j in range(self.num_vertexes):
if self._AM[i][j]:
v = self._V[j]
if v not in result: # not checked yet
result.append(v)
checking += 1
if checking == len(result):
finished = True
else:
v = result[checking]
return result
def topological_sort(self, algo="dfs"):
if algo == "kahn":
return self._kahn_topological_sort()
else:
return self._dfs_topological_sort()
''' 基于DFS的拓朴排序 '''
def _dfs_topological_sort(self):
result = []
for v in self._V:
if v not in result:
self.dfs(v, "post", result)
result.reverse()
return result
''' 基于Kahn算法的拓朴排序 '''
def _kahn_topological_sort(self):
result = []
# calc indegree and get zero degree set
indegree = [0 for i in range(self.num_vertexes)]
zero_degree_set = []
for e in self._E:
v_h, v_t = e
indegree[v_t] += 1
for i in range(self.num_vertexes):
if indegree[i] == 0:
zero_degree_set.append(i)
while len(zero_degree_set):
i = zero_degree_set.pop()
v = self._V[i]
result.append(v)
for j in range(self.num_vertexes):
if self._AM[i][j]:
indegree[j] -= 1
if indegree[j] == 0:
zero_degree_set.append(j)
return result
def test(V, E, AM, topology):
print "="*80
G = Digraph(V, E)
#print G._AM
#print AM
assert G._AM == AM
print topology
print "="*10 + "bfs" + "="*10
for v in V:
print v, G.bfs(v)
print "="*10 + "dfs pre order" + "="*10
for v in V:
print v, G.dfs(v, "pre")
print "="*10 + "dfs post order" + "="*10
for v in V:
print v, G.dfs(v, "post")
print "="*10 + "topological sort" + "="*10
print "dfs", G.topological_sort("dfs")
print "kahn", G.topological_sort("kahn")
def test1():
topology = \
'''
->v0------>v4
/ ^ ^
/ | |
v1 | |
\ | |
\ | |
->v2------>v3
'''
V = ["v0", "v1", "v2", "v3", "v4"]
E = [
(0, 4),
(1, 0),
(1, 2),
(2, 3),
(2, 0),
(3, 4),
]
AM = [ #v0,v1,v2,v3,v4
[0, 0, 0, 0, 1], # v0
[1, 0, 1, 0, 0], # v1
[1, 0, 0, 1, 0], # v2
[0, 0, 0, 0, 1], # v3
[0, 0, 0, 0, 0], # v4
]
test(V, E, AM, topology)
def test2():
topology = \
'''
0------------->6<---7<---8
| \ / \
| |\ / \
| v --<2 / \
| 1 / / ->9--->10
| 3<- / | \
| / ->4<- v \
|/ / 11--->12
v /
5--
'''
V = ["v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12"]
E = [
(0, 1),
(0, 5),
(0, 6),
(2, 0),
(2, 3),
(3, 5),
(5, 4),
(6, 4),
(6, 9),
(7, 6),
(8, 7),
(9, 10),
(9, 11),
(9, 12),
(11, 12),
]
AM = [ #v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12
[0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], # v0
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # v1
[1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], # v2
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], # v3
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # v4
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], # v5
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0], # v6
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], # v7
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], # v8
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], # v9
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # v10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], # v11
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # v12
]
test(V, E, AM, topology)
if __name__ == '__main__':
test1()
test2()
输出:
================================================================================ ->v0------>v4 / ^ ^ / | | v1 | | \ | | \ | | ->v2------>v3 ==========bfs========== v0 ['v0', 'v4'] v1 ['v1', 'v0', 'v2', 'v4', 'v3'] v2 ['v2', 'v0', 'v3', 'v4'] v3 ['v3', 'v4'] v4 ['v4'] ==========dfs pre order========== v0 ['v0', 'v4'] v1 ['v1', 'v0', 'v4', 'v2', 'v3'] v2 ['v2', 'v0', 'v4', 'v3'] v3 ['v3', 'v4'] v4 ['v4'] ==========dfs post order========== v0 ['v4', 'v0'] v1 ['v4', 'v0', 'v3', 'v2', 'v1'] v2 ['v4', 'v0', 'v3', 'v2'] v3 ['v4', 'v3'] v4 ['v4'] ==========topological sort========== dfs ['v1', 'v2', 'v3', 'v0', 'v4'] kahn ['v1', 'v2', 'v3', 'v0', 'v4'] ================================================================================ 0------------->6<---7<---8 | \ / \ | |\ / \ | v --<2 / \ | 1 / / ->9--->10 | 3<- / | \ | / ->4<- v \ |/ / 11--->12 v / 5-- ==========bfs========== v0 ['v0', 'v1', 'v5', 'v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v1 ['v1'] v2 ['v2', 'v0', 'v3', 'v1', 'v5', 'v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v3 ['v3', 'v5', 'v4'] v4 ['v4'] v5 ['v5', 'v4'] v6 ['v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v7 ['v7', 'v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v8 ['v8', 'v7', 'v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v9 ['v9', 'v10', 'v11', 'v12'] v10 ['v10'] v11 ['v11', 'v12'] v12 ['v12'] ==========dfs pre order========== v0 ['v0', 'v1', 'v5', 'v4', 'v6', 'v9', 'v10', 'v11', 'v12'] v1 ['v1'] v2 ['v2', 'v0', 'v1', 'v5', 'v4', 'v6', 'v9', 'v10', 'v11', 'v12', 'v3'] v3 ['v3', 'v5', 'v4'] v4 ['v4'] v5 ['v5', 'v4'] v6 ['v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v7 ['v7', 'v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v8 ['v8', 'v7', 'v6', 'v4', 'v9', 'v10', 'v11', 'v12'] v9 ['v9', 'v10', 'v11', 'v12'] v10 ['v10'] v11 ['v11', 'v12'] v12 ['v12'] ==========dfs post order========== v0 ['v1', 'v4', 'v5', 'v10', 'v12', 'v11', 'v9', 'v6', 'v0'] v1 ['v1'] v2 ['v1', 'v4', 'v5', 'v10', 'v12', 'v11', 'v9', 'v6', 'v0', 'v3', 'v2'] v3 ['v4', 'v5', 'v3'] v4 ['v4'] v5 ['v4', 'v5'] v6 ['v4', 'v10', 'v12', 'v11', 'v9', 'v6'] v7 ['v4', 'v10', 'v12', 'v11', 'v9', 'v6', 'v7'] v8 ['v4', 'v10', 'v12', 'v11', 'v9', 'v6', 'v7', 'v8'] v9 ['v10', 'v12', 'v11', 'v9'] v10 ['v10'] v11 ['v12', 'v11'] v12 ['v12'] ==========topological sort========== dfs ['v8', 'v7', 'v2', 'v3', 'v0', 'v6', 'v9', 'v11', 'v12', 'v10', 'v5', 'v4', 'v1'] kahn ['v8', 'v7', 'v2', 'v3', 'v0', 'v6', 'v9', 'v11', 'v12', 'v10', 'v5', 'v4', 'v1']