在没有递归的情况下找到到达一定深度的所有路径中n元树的所有唯一节点

问题描述

我正在尝试用Python编写算法,以获取路径到达​​特定深度的树中所有节点的唯一列表。

  • 每个孩子在遍历之前有未知数目的孩子
  • 可以通过可迭代的方式(例如for child in B.get_children())访问子级

例如,请参见此树(应包括星号标记节点):

       A*
       |
     -----
    |     |
    B*    C*
    |     |
    |    ---
    |   |   |
    D*  E   F*
  / | \     | \
 G* H* I*   J* K*
               |
               L

比方说,我试图达到3的深度。我需要一个能够以任意顺序产生序列[G,H,I,J,K,D,F,B,C,A]的函数。

请注意:

  • E(深度不超过3)
  • L(深度超过3)

我觉得有一种方法可以递归获取此列表。类似于:

def iterate_tree(path: List[T],all_nodes: Set[T]):
    if len(path) == 4:
        for node in path:
            if node not in all_nodes:
                all_nodes.add(node)
                yield node
    else:
        for node in path[-1].get_children():
            path = path.copy()
            path.append(node)
            yield from iterate_tree(path,all_nodes)

iterate_tree([A],set())

我不知道上面的方法是否有效,但是我认为可以从中破解。对于(可能不正确的)解决方案,我不满意的是:

  1. 递归:我正在写这个未知的深度。我不要堆栈溢出。
  2. 我真的觉得必须有一种方法可以在不携带set个先前的yielded个节点的情况下进行此操作。
  3. 我必须在每次迭代时复制path的副本,以免弄乱递归的其他分支。

有什么建议吗?

解决方法

对于第1点,您可以使用显式堆栈循环而不是递归。

对于第二点,我不确定保留一组屈服节点是否存在问题。内存很便宜,如果您需要检测重复的内存,那么每次生成树时都要遍历树非常昂贵。

此外,您的实现基于节点哈希性检查唯一性,但是还不清楚节点如何计算其哈希。我假设您为此使用Node.val。如果您基于对象引用进行哈希处理,则“唯一性”似乎毫无意义,因为可以确保节点对象树按身份是唯​​一的。此处的示例并未显示出唯一性的冲突。我的实现假定散列是对象身份(应该是对象身份),并且您可以使用Node.val单独访问唯一性值。

对于第3点,如果您是递归工作,则无需复制路径列表,因为您可以重新访问调用框架并可以在单个列表上追加/弹出。迭代地,您可以在parent_of集旁边保留一个nodes_yielded字典,该集合保留对每个节点的父节点的引用。当我们到达所需深度的节点时,我们可以遍历此字典中的链接来重建路径,而不必担心多次使用nodes_yielded重新访问分支。第二组vals_yielded可用于对收益率实施唯一性。

最后,我真的不知道您的数据结构是什么,因此为了minimal,complete example的利益,我提供了一些适合您的内容。

import collections

def unique_nodes_on_paths_to_depth(root,depth):
    parent_of = {root: None}
    nodes_yielded = set()
    vals_yielded = set()
    stack = [(root,depth)]

    while stack:
        node,depth = stack.pop()

        if depth == 0:
            while node and node not in nodes_yielded:
                if node.val not in vals_yielded:
                    vals_yielded.add(node.val)
                    yield node

                nodes_yielded.add(node)
                node = parent_of[node]
        elif depth > 0:
            for child in node.children:
                parent_of[child] = node
                stack.append((child,depth - 1))

if __name__ == "__main__":
    """
           A*
           |
         -----
        |     |
        B*    C*
        |     |
        |    ---
        |   |   |
        D*  E   F*
      / | \     | \
     G* H* I*   J* K*
                   |
                   L
    """
    Node = collections.namedtuple("Node","val children")
    root = Node("A",(
        Node("B",(
            Node("D",(
                Node("G",()),Node("H",Node("I",)),Node("C",(
            Node("E",Node("F",(
                Node("J",Node("K",(
                    Node("L",))
    ))
    print([x.val for x in unique_nodes_on_paths_to_depth(root,3)])
    #      => ['K','F','C','A','J','I','D','B','H','G'] 

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...