拓朴排序

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

  

posted @ 2018-04-10 17:41  ZisZ  阅读(284)  评论(0编辑  收藏  举报