我正在python中动态实现一棵树。我已经定义了一个类,如下所示
class nodeobject():
def __init__(self,presentnode=None,parent=None):
self.currentNode = presentnode
self.parentNode = parent
self.childs = []
我有一个函数可以从池中获取每个节点的子项
def findchildren(node, childs):` `# No need to write the whole function on how it gets childs
现在我有一个以头节点(没有父节点)开头的递归函数,并为每个节点递归地向下移动链(基本情况是没有子节点的最后一个节点)
def tree(dad,children):
for child in children:
childobject = nodeobject(child,dad)
dad.childs.append(childobject)
newchilds = findchildren(child, children)
if len(newchilds) == 0:
lastchild = nodeobject(newchilds,childobject)
childobject.childs.append(lastchild)
loopchild = copy.deepcopy(lastchild)
while loopchild.parentNode != None:
print "last child"
result.append(loopchild.currentNode) # result global to store values
loopchild = copy.deepcopy(loopchild.parentNode)
else:
tree(childobject,newchilds)
树形成仅适用于特定数量的输入。一旦池变大,就会导致“最大退回深度超过”
我尝试使用set.recursionlimit()设置递归限制,但它不起作用。程序崩溃了。我想为递归实现一个堆栈,有人可以请求帮助,即使经过很长一段时间后我也没有去过哪里?另外,除了堆栈之外还有其他方法来解决这个问题吗?
答案 0 :(得分:3)
当您尝试更改递归深度时,您的程序可能会崩溃,因为您超出了系统上堆栈大小所施加的硬递归限制。设置sys.recursionlimit()只会使Python对深度不那么严格,但它不会影响你的平台实际支持的内容。
Python有一个相当天真的递归实现,这意味着它只有在保证你的递归深度相当低时才有用。首先检查你的树真的足够深,可以吹掉堆栈;如果任何节点都有孩子也是他们的父母/祖先,这段代码将尝试永远运行,直到它耗尽堆栈。检查的一种方法是跟踪findchildren()
返回的所有节点,并确保它们永远不会重复。
如果您的数据正确且堆栈确实不够深,则必须将代码转换为迭代版本并手动构建自己的堆栈。这是你的代码有一个显式堆栈(我没有测试过,所以可能有错误,但它应该让你知道如何做到这一点):
def tree(dad, children):
stack = [(dad, children)]
while stack:
dad, children = stack.pop()
for index, child in enumerate(children):
childobject = nodeobject(child,dad)
dad.childs.append(childobject)
newchilds = findchildren(child, children)
if len(newchilds) == 0:
lastchild = nodeobject(newchilds,childobject)
childobject.childs.append(lastchild)
loopchild = copy.deepcopy(lastchild)
while loopchild.parentNode != None:
print "last child"
result.append(loopchild.currentNode) # result global to store values
loopchild = copy.deepcopy(loopchild.parentNode)
else:
stack.append((dad, children[index:]))
stack.append((childobject,newchilds))
break
需要注意的一个重要特性是,在推送新的子节点之前,我们必须将尚未在for循环中处理的子节点推回堆栈。
@Peter Gibson提出了一个很好的观点,你可能不希望对你的节点进行深度复制,但是这不应该导致你的堆栈爆炸(只是耗尽大量的内存而没有我能看到的任何好处)。< / p>
答案 1 :(得分:0)
我会说这段代码是问题所在:
loopchild = copy.deepcopy(lastchild)
while loopchild.parentNode != None:
print "last child"
result.append(loopchild.currentNode) # result global to store values
loopchild = copy.deepcopy(loopchild.parentNode)
你遍历树直到你到达一片叶子(没有孩子的孩子),然后你将每个节点的deepcopy
带回到开始。
deepcopy
制作了nodeobject
的副本,以及parentNode
的副本以及childs
中的每个孩子的副本。这意味着deepcopy
的{{1}}中的每一个nodeobject
都是整个树的副本以及所有数据!
考虑一个4级深度的简单树,例如
A
B C
D E F G
H I J K L M N O
当它落到第一片叶子H
时,它会生成deepcopy
个节点H
,D
,B
和&amp; A
- 每个都是整棵树和所有数据的副本。因此,对于这个相当简单的结构,您最终会获得32份副本!我可以看到这很快就会失去控制。
您是否有理由制作每个节点的副本?尝试用
替换该代码 loopchild = lastchild
while loopchild.parentNode != None:
print "last child"
result.append(loopchild.currentNode) # result global to store values
loopchild = loopchild.parentNode