最近接触了一下拓朴排序,手痒写了下代码,给自己找了点麻烦,dfs特地没有用递归做;
关于拓朴排序的原理有很多人写得很好了,请参考以下文章:
https://blog.csdn.net/qinzhaokun/article/details/48541117
https://blog.csdn.net/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']