zoukankan      html  css  js  c++  java
  • 拓朴排序

    最近接触了一下拓朴排序,手痒写了下代码,给自己找了点麻烦,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']
    

      

  • 相关阅读:
    数组
    对象
    js继承
    js原型原型链
    es6(初级)
    canvas背景
    Angular.js进阶
    Angular.js-2入门
    angular.js-1初识
    js之广告
  • 原文地址:https://www.cnblogs.com/ZisZ/p/8780892.html
Copyright © 2011-2022 走看看