拓扑排序蟒蛇 [英] Topological sort python

查看:161
本文介绍了拓扑排序蟒蛇的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I codeD的DFS非递归的解决方案,但我不能修改它,使拓扑排序:

 高清DFS(图,开始):
    路径= []
    堆栈= [开始]
    而堆栈= []!
        V = stack.pop()
        如果v不是路径:path.append(五)
        为瓦特在逆转(图[V]):
            当w不在路径,而不是中W堆栈:
                stack.append(w)的
    返回路径
 

任何想法如何修改?

使用递归的版本,我可以轻松拥有排序:

 高清dfs_rec(图,启动,路):
    路径=路径+ [开始]
    在图形边缘[开始]:
        如果不是在道路边:
            PATH = dfs_rec(图,边,路径)
    打印开始
    返回路径
 

输入:

 >>>图= {
        1:[2,3]
        2:[4,5,6]中
        3:[4,6],
        4:[5,6],
        5:[6],
        6:[]
    }
>>> dfs_rec(曲线图中,1,[])
6
五
4
2
3
1
[1,2,4,5,6,3]
>>> DFS(图中,1)
[1,2,4,5,6,3]
>>>图= {
        1:[3],
        3:[5,6],
        5:[4],
        4:[7],
        7:[],
        6:[]
    }
>>>打印dfs_rec(图1,[])
7
4
五
6
3
1
[1,3,5,4,7,6]
>>>打印DFS(图1)
[1,3,5,4,7,6]
 

所以我需要得到这个排序的非递归也。

非递归解决方案:

我认为,这也可能是解决方案,标志着我,如果我错了。

 高清DFS(图,开始):
    路径= []
    堆栈= [开始]
    标签的len =(图形)
    结果= {}
    而堆栈= []!
        #这个循环可以其它方式进行也
        在堆栈中的元素:
            如果元素不是结果:
                结果[元] =标签
                标签=标签 -  1

        V = stack.pop()
        如果v不是路径:path.append(五)
        为瓦特在逆转(图[V]):
            当w不在路径,而不是中W堆栈:
                stack.append(w)的

    结果= {V:K代表K,V在result.items()}
    返回路径,导致
 

输入:

图表= {1:[3],3:[5,6],5:[4],4:[7],7:[],6:[] }
打印DFS(图1)
 

输出:

([1,3,5,4,7,6],{1:7,2:4,3:5,4:6,5:3,6: 1})

        1
       /
      3
     / \
    5 6
   /
  4
 /
7
 

解决方案

您似乎递归的解决方案并没有被生产拓扑排序输出。

例如使用该输入:

 图= {
    1:[2,11],
    2:[3],
    11:[12],
    12:[13]
    }


      1
      / \
     / 11
    / \
   2月12日
  / \
 3 13
 

我们应该得到 13 之前 2

但你的递归code的输出是:

  3
2
13
12
11
1
 

13 下面 2

尽管它应该是:

  3
13
2
12
11
1
 

另外,变量路径似乎只是探索节点,必须与路径无关(因此应当设置,没有下令列表,要进行查找更有效)。

这一切都使得它很难把握你的code和纠正非递归版本,给出的递归没有做它应该。


我刚刚制作的递归解决方案,这使得拓扑排序。它遍历所有的图与深度优先搜索,并保持与相关的层次遍历的节点的词典作为值:

 从收藏导入defaultdict
从itertools进口takewhile,算

高清sort_topologically(图表):
    levels_by_name = {}
    names_by_level = defaultdict(套)

    高清walk_depth_first(名):
        如果名levels_by_name:
            回报levels_by_name [名]
        儿童= graph.get(名称,无)
        级别= 0,如果没有其他的孩子(1 + MAX(walk_depth_first(L-NAME)的LNAME儿童))
        levels_by_name [名] =级别
        names_by_level [等级]。新增(名称)
        回报水平

    在图名称:
        walk_depth_first(名)

    返回表(takewhile(拉姆达X:X是不是无,(names_by_level.get(ⅰ,无)为i的计数())))


图= {
        1:[2,3]
        2:[4,5,6]中
        3:[4,6],
        4:[5,6],
        5:[6],
        6:[]
    }

打印(sort_topologically(图))
 


下面是一个无堆栈版本。我还没有调试它彻底,但它似乎是工作。

 从收藏导入defaultdict
从itertools进口takewhile,算

高清sort_topologically_stackless(图表):
    levels_by_name = {}
    names_by_level = defaultdict(套)

    高清add_level_to_name(名称,等级):
        levels_by_name [名] =级别
        names_by_level [等级]。新增(名称)


    高清walk_depth_first(名):
        堆栈= [名]
        而(栈):
            NAME = stack.pop()
            如果名levels_by_name:
                继续

            如果名称不图形或不绘制[名]:
                级别= 0
                add_level_to_name(名称,等级)
                继续

            孩子=图[名]

            children_not_calculated = [孩子的孩子的孩子,如果孩子不levels_by_name]
            如果children_not_calculated:
                stack.append(名)
                stack.extend(children_not_calculated)
                继续

            级别= 1 + MAX(levels_by_name [L-NAME]为LNAME儿童)
            add_level_to_name(名称,等级)

    在图名称:
        walk_depth_first(名)

    返回表(takewhile(拉姆达X:X是不是无,(names_by_level.get(ⅰ,无)为i的计数())))


图= {
        1:[2,3]
        2:[4,5,6]中
        3:[4,6],
        4:[5,6],
        5:[6],
        6:[]
    }

打印(sort_topologically_stackless(图))
 

I coded a solution for DFS non-recursive, but i can't modify it to make a topological sort:

def dfs(graph,start):
    path = []
    stack = [start]    
    while stack != []: 
        v = stack.pop()
        if v not in path: path.append(v)
        for w in reversed(graph[v]): 
            if w not in path and not w in stack:
                stack.append(w) 
    return path

Any ideas how to modify it?

With the recursive version i can easy have the sorting:

def dfs_rec(graph,start,path):
    path = path + [start]
    for edge in graph[start]: 
        if edge not in path:
            path = dfs_rec(graph, edge,path)
    print start
    return path

Input:

>>> graph = {
        1: [2, 3],
        2: [4, 5, 6],
        3: [4,6],
        4: [5,6],
        5: [6],
        6: []
    }
>>> dfs_rec(graph,1,[])
6
5
4
2
3
1
[1, 2, 4, 5, 6, 3]
>>> dfs(graph,1)
[1, 2, 4, 5, 6, 3]
>>> graph = {
        1: [3],
        3: [5,6],
        5: [4],
        4: [7],
        7: [],
        6: []
    }
>>> print dfs_rec(graph,1,[])
7
4
5
6
3
1
[1, 3, 5, 4, 7, 6]
>>> print dfs(graph,1)
[1, 3, 5, 4, 7, 6]

so i need to get this ordering in the non-recursive also.

Non-recursive solution:

I think that this also could be the solution, mark me if i am wrong.

def dfs(graph,start):
    path = []
    stack = [start]
    label = len(graph)
    result = {}  
    while stack != []:
        #this for loop could be done in other ways also
        for element in stack:
            if element not in result:
                result[element] = label
                label = label - 1

        v = stack.pop()
        if v not in path: path.append(v)
        for w in reversed(graph[v]): 
            if w not in path and not w in stack:
                stack.append(w) 

    result = {v:k for k, v in result.items()}
    return path,result

Input:

graph = { 1: [3], 3:[5,6] , 5:[4] , 4:[7], 7:[],6:[]}
print dfs(graph,1) 

Output:

([1, 3, 5, 4, 7, 6], {1: 7, 2: 4, 3: 5, 4: 6, 5: 3, 6: 1})

        1
       / 
      3
     /\
    5  6
   /
  4
 /
7    

解决方案

You recursive solution doesn't seem to be producing topologically sorted output.

For example with this input:

graph = {
    1: [2,11],
    2: [3],
    11: [12],
    12: [13]
    }


      1
      /\
     / 11
    /    \
   2     12
  /        \
 3         13

we should get 13 prior to 2.

But the output of your recursive code is:

3
2
13
12
11
1

with 13 following2.

While it should be:

3
13
2
12
11
1

Furthermore, the variable path seems to be just explored nodes and has nothing to do with path (and thus it should be set, not ordered list, to be more efficient for lookups).

All this makes it very difficult to grasp your code and correct the non-recursive version, given the recursive doesn't do what it should.


I've just crafted a recursive solution which makes a topological sorting. It traverses all the graph with depth-first-search and keeps a dictionary of traversed nodes with associated levels as values:

from collections import defaultdict
from itertools import takewhile, count

def sort_topologically(graph):
    levels_by_name = {}
    names_by_level = defaultdict(set)

    def walk_depth_first(name):
        if name in levels_by_name:
            return levels_by_name[name]
        children = graph.get(name, None)
        level = 0 if not children else (1 + max(walk_depth_first(lname) for lname in children))
        levels_by_name[name] = level
        names_by_level[level].add(name)
        return level

    for name in graph:
        walk_depth_first(name)

    return list(takewhile(lambda x: x is not None, (names_by_level.get(i, None) for i in count())))


graph = {
        1: [2, 3],
        2: [4, 5, 6],
        3: [4,6],
        4: [5,6],
        5: [6],
        6: []
    }

print(sort_topologically(graph))


Here is a stackless version. I haven't debugged it thoroughly, but it seems to be working.

from collections import defaultdict
from itertools import takewhile, count

def sort_topologically_stackless(graph):
    levels_by_name = {}
    names_by_level = defaultdict(set)

    def add_level_to_name(name, level):
        levels_by_name[name] = level
        names_by_level[level].add(name)


    def walk_depth_first(name):
        stack = [name]
        while(stack):
            name = stack.pop()
            if name in levels_by_name:
                continue

            if name not in graph or not graph[name]:
                level = 0
                add_level_to_name(name, level)
                continue

            children = graph[name]

            children_not_calculated = [child for child in children if child not in levels_by_name]
            if children_not_calculated:
                stack.append(name)
                stack.extend(children_not_calculated)
                continue

            level = 1 + max(levels_by_name[lname] for lname in children)
            add_level_to_name(name, level)

    for name in graph:
        walk_depth_first(name)

    return list(takewhile(lambda x: x is not None, (names_by_level.get(i, None) for i in count())))


graph = {
        1: [2, 3],
        2: [4, 5, 6],
        3: [4,6],
        4: [5,6],
        5: [6],
        6: []
    }

print(sort_topologically_stackless(graph))

这篇关于拓扑排序蟒蛇的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆