[英]How to delete all nodes of a Binary Search Tree
我正在尝试编写代码以删除BST的所有节点(每个节点只有三个属性,left,right和data,没有父指针)。 以下代码是我想出的,它仅删除树的右半部分,而保留左半部分不变。 我该如何修改它以使左半部分也被删除(以便最终我只剩下没有左或右子树的根节点)?
def delete(root):
global last
if root:
delete(root.left)
delete(root.right)
if not (root.left or root.right):
last = root
elif root.left == last:
root.left = None
else:
root.right = None
其次,有人可以使用堆栈或其他相关数据结构来建议一种迭代方法吗?
如果要删除两个子树,则无需递归。 只需将root.left
和root.right
设置为None
然后让垃圾收集器来处理它们。 确实,不必首先设置delete
功能,只需设置root = None
完成!
编辑:如果您需要对数据值运行清除代码,如果GC做得不够好,您可能需要遍历树以获取所有数据。 确实没有必要删除树中的链接,但是我也将采取适当的措施:
def delete(node):
if node:
node.data.cleanup() # run data value cleanup code
delete(node.left) # recurse
delete(node.right)
node.data = None # clear pointers (not really necessary)
node.left = None
none.right = None
您还询问了遍历树的迭代方法,这种方法稍微复杂一些。 这是一种使用deque
(作为堆栈)遍历祖先的方法:
from collections import deque
def delete_iterative(node):
stack = deque()
last = None
# start up by pushing nodes to the stack until reaching leftmost node
while node:
stack.append(node)
node = node.left
# the main loop
while stack:
node = stack.pop()
# should we expand the right subtree?
if node.right && node.right != last: # yes
stack.append(node)
node = node.right
while node: # expand to find leftmost node in right subtree
stack.append(node)
node = node.left
else: # no, we just came from there (or it doesn't exist)
# delete node's contents
node.data.cleanup()
node.data = None # clear pointers (not really necessary)
node.left = None
node.right = None
# let our parent know that it was us it just visited
last = node
Blckknght关于垃圾回收是正确的,但是如果您想进行比示例所建议的更为复杂的清理,或者理解为什么您的代码不起作用,我将提供一个附加的答案:
您的问题似乎是elif node.left == last
检查。
我不确定您的last
变量是用来做什么的,或者它背后的逻辑是什么。
但是问题在于node.left
几乎永远不会等于last
(如果两个子节点都已经设置为None
,则仅将节点分配给last
变量,对于任何有趣的节点(具有子节点的节点)来说,它们都不是。 )。
如果看一下代码,您会发现如果node.left
不等于last
只有正确的孩子被设置为None
,因此只有子树的右边被删除。
我不知道python,但这应该可以工作:
def delete(node):
if node:
# recurse: visit all nodes in the two subtrees
delete(node.left)
delete(node.right)
# after both subtrees have been visited, set pointers of this node to None
node.left = None
node.right = None
(我把你的重命名的自由root
参数node
,因为给该函数的节点不一定是树的根节点。)
使用堆栈的迭代后遍历可能看起来像这样:
def is_first_visit(cur, prev):
return prev is None or prev.left is cur or prev.right is cur
def visit_tree(root):
if root:
todo = [root]
previous = None
while len(todo):
node = todo[-1]
if is_first_visit(node, previous):
# add one of our children to the stack
if node.left:
todo.append(node.left)
elif node.right:
todo.append(node.right)
# now set previous to ourself and continue
elif previous is node.left:
# we've done the left subtree, do right subtree if any
if node.right:
todo.append(node.right)
else:
# previous is either node.right (we've visited both sub-trees)
# or ourself (we don't have a right subtree)
do_something(node)
todo.pop()
previous = node
do_something
做您想调用的“实际上删除此节点”。
您可以通过在每个节点上设置一个属性来声明它是否已经调用过do_something
来做一些简单的事情,但是显然,如果您的节点上有__slots__
或其他内容,并且您不希望这样做,该方法就不能很好地工作修改节点类型以允许该标志。
我不确定在递归调用之后您对这些条件做什么,但是我认为这应该足够了:
def delete(root):
if root:
delete(root.left)
delete(root.right)
root = None
正如注释中指出的那样,Python不会通过引用传递参数。 在这种情况下,您可以像这样在Python中完成这项工作:
def delete(root):
if root:
delete(root.left)
delete(root.right)
root.left = None
root.right = None
Usage:
delete(root)
root = None
至于迭代方法,您可以尝试一下。 这是伪代码,我不懂python。 基本上,我们进行BF搜索。
delete(root):
make an empty queue Q
Q.push(root)
while not Q.empty:
c = Q.popFront()
Q.push(c.left, c.right)
c = None
同样,如果您将根用作功能,则默认情况下不会修改根,但是它将删除所有其他节点。 您可以在函数调用之后将根设置为“无”,或者删除参数并使用全局根变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.