很抱歉,如果这是一个常见问题,但是我没有找到适合我特定问题的适当答案。我正在尝试实现一种walk
方法,该方法将二叉树从其根节点移动到其每个叶节点,并在到达叶节点时生成从根到叶的路径。例如,遍历由以下表示的二叉树:
__a__
/ \
b d
/ \ / \
- c - -
会产生:
['a', 'b', 'c']
['a', 'd']
我的想法是BinaryTree.walk
在根节点上调用Node.traverse
,而根节点又递归地调用每个子节点的traverse
方法。 BinaryTree.walk
还会创建一个空列表,每次调用traverse
时都会传递一个空列表,附加每个节点的数据,一旦到达叶节点,就产生该列表,并在访问每个元素后将每个元素从列表中弹出节点。
在某些时候,尽管出了点问题。这是我的代码:
class Node:
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
def __repr__(self):
return f"{self.__class__.__name__}({self.data})"
@property
def children(self):
return self.left, self.right
def traverse(self, branch):
print('ON NODE:', self)
branch.append(self.data)
if self.left is None and self.right is None:
yield branch
else:
for child in self.children:
if child is not None:
print('ENTERING CHILD:', child)
child.traverse(branch=branch)
print('EXITING CHILD:', child)
branch.pop()
class BinaryTree:
def __init__(self, root=Node()):
if not isinstance(root, Node):
raise ValueError(f"Tree root must be Node, not {type(root)}")
self.root = root
def __repr__(self):
return f"{self.__class__.__name__}({self.root})"
def walk(self):
node = self.root
branch = []
yield from node.traverse(branch=branch)
if __name__ == '__main__':
# create root node
n0 = Node('A')
# create binary tree with root node
tree = BinaryTree(root=n0)
# create others nodes
n1 = Node(data='B')
n2 = Node(data='C')
n3 = Node(data='D')
# connect nodes
n0.left = n1
n0.right = n3
n1.right = n2
# walk tree and yield branches
for branch in tree.walk():
print(branch)
ON NODE: Node(A)
ENTERING CHILD: Node(B)
ON NODE: Node(B)
ENTERING CHILD: Node(C)
ON NODE: Node(C)
['A', 'B', 'C'] # yielded branch
EXITING CHILD: Node(C)
EXITING CHILD: Node(B)
ENTERING CHILD: Node(D)
ON NODE: Node(D)
['A', 'D'] # yielded branch
EXITING CHILD: Node(D)
ON NODE: Node(A)
ENTERING CHILD: Node(B)
EXITING CHILD: Node(B)
ENTERING CHILD: Node(D)
EXITING CHILD: Node(D)
IndexError: pop from empty list
我知道我对列表做错了,因为它在空时尝试弹出,但是我不明白它是如何到达的。对于每个pop
调用,它应该调用一次append
。
我也不知道为什么要输入和退出节点,但是没有显示ON NODE:
消息...就像我的代码以某种方式跳过了child.traverse(branch=branch)
行一样?< / p>
有人可以帮助我了解我在哪里搞砸吗?
在此先感谢您的帮助!
答案 0 :(得分:1)
一个很好的答案here
复制其Python示例:
"""
Python program to print all path from root to
leaf in a binary tree
"""
# binary tree node contains data field ,
# left and right pointer
class Node:
# constructor to create tree node
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# function to print all path from root
# to leaf in binary tree
def printPaths(root):
# list to store path
path = []
printPathsRec(root, path, 0)
# Helper function to print path from root
# to leaf in binary tree
def printPathsRec(root, path, pathLen):
# Base condition - if binary tree is
# empty return
if root is None:
return
# add current root's data into
# path_ar list
# if length of list is gre
if(len(path) > pathLen):
path[pathLen] = root.data
else:
path.append(root.data)
# increment pathLen by 1
pathLen = pathLen + 1
if root.left is None and root.right is None:
# leaf node then print the list
printArray(path, pathLen)
else:
# try for left and right subtree
printPathsRec(root.left, path, pathLen)
printPathsRec(root.right, path, pathLen)
# Helper function to print list in which
# root-to-leaf path is stored
def printArray(ints, len):
for i in ints[0 : len]:
print(i," ",end="")
print()
# Driver program to test above function
"""
Constructed binary tree is
10
/ \
8 2
/ \ /
3 5 2
"""
root = Node(10)
root.left = Node(8)
root.right = Node(2)
root.left.left = Node(3)
root.left.right = Node(5)
root.right.left = Node(2)
printPaths(root)
# This code has been contributed by Shweta Singh.
赠予:
10 8 3
10 8 5
10 2 2
您也可以给它字母:
root = Node("A")
root.left = Node("B")
root.right = Node("D")
root.left.right = Node("C")
printPaths(root)
赠予:
A B C
D
答案 1 :(得分:1)
这是您代码的变体。
code.py :
#!/usr/bin/env python3
import sys
class Node:
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
def __repr__(self):
return f"{self.__class__.__name__}({self.data})"
@property
def children(self):
if self.left:
yield self.left
if self.right:
yield self.right
@property
def is_leaf(self):
return self.left is None and self.right is None
def traverse_preord(self, accumulator=list()):
print(" On node:", self)
accumulator.append(self.data)
if self.is_leaf:
yield accumulator
else:
for child in self.children:
print(" Entering child:", child)
yield from child.traverse_preord(accumulator=accumulator)
accumulator.pop()
print(" Exiting child:", child)
def main():
root = Node(data="A",
left=Node(data="B",
right=Node(data="C")
),
right=Node(data="D",
#left=Node(data="E"),
#right=Node(data="F"),
)
)
for path in root.traverse_preord():
print("Found path:", path)
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
注释:
输出:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055424449]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32 On node: Node(A) Entering child: Node(B) On node: Node(B) Entering child: Node(C) On node: Node(C) Found path: ['A', 'B', 'C'] Exiting child: Node(C) Exiting child: Node(B) Entering child: Node(D) On node: Node(D) Found path: ['A', 'D'] Exiting child: Node(D)
这是遍历重复调用(child.traverse(branch=branch)
)。 它创建了一个生成器,但是由于未在任何地方使用(迭代)该函数,因此实际上并未对其进行调用,导致尝试删除的元素多于添加的元素(仅 < em> 1 :这是根节点)。
所以事实证明你快到了。您所要做的就是在其前面添加 yield from
:)。
有关[Python]: PEP 380 -- Syntax for Delegating to a Subgenerator的更多详细信息。