【问题标题】:DAG - Iterate over graph - bfs but parents firstDAG - 遍历图 - bfs 但父母优先
【发布时间】:2022-08-17 22:08:28
【问题描述】:

你好,我有一个看起来像这样的 dag

我想从根部开始旅行并打印输出,例如

1 6
2 3
4
5

我尝试过这样的事情,但它仍然无法正常工作。有人可以给我一个关于这种算法应该是什么样子或这种图遍历的名称的提示吗?

from typing import List


class Node:
    def __init__(self, value, children) -> None:
        super().__init__()
        self.value = value
        self.children = children

    @staticmethod
    def create(value, *parents):
        node = Node(value, [])
        if parents is not None:
            for parent in parents:
                parent.children.append(node)
        return node


def travel(roots: List[Node], visited: List[Node]):
    print(\" \".join([str(r.value) for r in roots]))
    visited += roots
    all_children = []
    for r in roots:
        if r.children:
            for c in r.children:
                if c not in visited:
                    all_children.append(c)
    if all_children:
        travel(all_children, visited)


if __name__ == \'__main__\':
    root = Node.create(1)
    root2 = Node.create(6)
    roots = [root, root2]
    n2 = Node.create(2, root)
    n3 = Node.create(3, root)
    n4 = Node.create(4, n2, n3, root2)
    n5 = Node.create(5, n4)
    travel(roots, [])
  • 你如何决定[2,3]4 的优先级?因为两者都与根的距离为 1?
  • 4 取决于 2,3 所以它需要等待它们
  • 我想你正在寻找topological sort

标签: python algorithm graph directed-acyclic-graphs


【解决方案1】:

您可以像以前一样首先遍历所有节点,然后为每个节点注册它有多少父节点。

根据节点的父节点数量将节点放入优先队列中。这可以实现为一个普通列表,其中索引表示父节点的数量,关联的值是具有该数量父节点的节点列表。

然后根据该优先级队列输出所有没有父节点的节点。同时将它们从该优先级队列中删除,并减少这些节点的子节点的父计数。

重复此过程,直到队列为空。

def travel(roots: List[Node]):
    # Build dictionary keyed by node to register their number of parents
    parentcount: Dict[Node, int] = { node: 0 for node in roots }
    # Visit each node, and update that parent count for each of its children
    visited: Set[Node] = set()
    nodes: List[Node] = roots
    while nodes:
        nextlevel: List[Node] = []
        for node in nodes:
            if node not in visited and node.children:
                for child in node.children:
                    parentcount[child] = parentcount.get(child, 0) + 1
                nextlevel.extend(node.children)
        visited.update(nodes)
        nodes = nextlevel
    # Make prioritiy queue: reverse the parentcount information: 
    #    group nodes that have the same parent count
    buckets: List[Set[Node]] = [set() for _ in visited]
    for node in visited:
        buckets[parentcount[node]].add(node)
    # Now we have the information to generate the output
    while buckets[0]:
        # Output nodes that have a parent count of 0. 
        nodes: List[Node] = list(buckets[0])
        buckets[0].clear()
        print(" ".join(str(node.value) for node in nodes))
        # Decrease the parent count of their children
        for node in nodes:
            if node.children:
                for child in node.children:
                    buckets[parentcount[child]].remove(child)
                    parentcount[child] -= 1
                    buckets[parentcount[child]].add(child)

注意:这个函数不再接受第二个参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多