Python 在到达某一深度的所有路径中查找n元树的所有唯一节点,无需递归
我正在尝试用Python编写一个算法,以获得树中路径达到一定深度的所有节点的唯一列表Python 在到达某一深度的所有路径中查找n元树的所有唯一节点,无需递归,python,recursion,tree,tree-traversal,Python,Recursion,Tree,Tree Traversal,我正在尝试用Python编写一个算法,以获得树中路径达到一定深度的所有节点的唯一列表 在遍历之前,每个子对象都有未知数量的子对象 可以通过iterable(例如B.get_children()中的child的)访问子项 例如,请参见此树(应包括的星号标记节点): 假设我正在尝试达到3的深度。我需要一个函数,它可以生成任意顺序的序列[G,H,I,J,K,D,F,B,C,a] 请注意,省略了: E(深度未达到3) L(深度超过3) 我觉得有一种方法可以递归地得到这个列表。大致如下: def
- 在遍历之前,每个子对象都有未知数量的子对象
- 可以通过iterable(例如B.get_children()中的child的
)访问子项
[G,H,I,J,K,D,F,B,C,a]
请注意,省略了:
(深度未达到3)E
(深度超过3)L
def iterate_树(路径:List[T],所有_节点:Set[T]):
如果len(路径)==4:
对于路径中的节点:
如果节点不在所有_节点中:
所有_节点。添加(节点)
屈服点
其他:
对于路径[-1]中的节点,获取子节点():
path=path.copy()
path.append(节点)
从迭代树(路径,所有节点)生成
迭代_树([A],set())
我不知道上述方法是否有效,但我想我可以从中破解。我不喜欢(可能不正确)解决方案的地方是:
节点的集合
path
,这样我就不会弄乱递归的其他分支有什么建议吗?对于第1点,您可以使用显式堆栈和循环,而不是递归 对于第2点,我不确定我是否看到了保留一组已生成节点的问题。内存很便宜,如果您需要检测重复项,那么每次生成时都要重新遍历树是非常昂贵的 此外,您的实现基于节点散列性检查唯一性,但不清楚节点如何计算其散列。我假设您使用的是
Node.val
。如果您是基于对象引用进行散列,“唯一性”似乎毫无意义,因为您可以保证节点对象的树在标识上是唯一的。这里的例子并没有说明唯一性上的冲突会带来什么。我的实现假设散列是对象标识(应该是),并且您可以使用Node.val
单独访问唯一性值
对于第3点,如果您以递归方式工作,则无需复制路径列表,因为您可以重新访问调用帧,并且可以在单个列表上追加/弹出。以迭代方式,您可以将dict的父节点_与生成的节点_集合一起保留,该集合保留对每个节点父节点的引用。当我们到达所需深度的节点时,我们可以遍历此字典中的链接以重建路径,避免由于节点而多次访问分支。第二组,vals_generated
可用于强制收益率的唯一性
最后,我真的不知道你的数据结构是什么,所以为了a的利益,我提供了一些应该适合你的东西
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']
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']