我正在使用以下代码:
import random
from time import time
class BinaryNode:
def __init__(self, value = None):
"""Create binary node"""
self.value = value
self.left = None
self.right = None
def add(self, val):
"""Adds a new node to the tree containing this value"""
if val <= self.value:
if self.left:
self.left.add(val)
else:
self.left = BinaryNode(val)
else:
if self.right:
self.right.add(val)
else:
self.right = BinaryNode(val)
def delete(self):
"""
Remove value of self from BinaryTree. Works in conjunction with remove
method in BinaryTree
"""
if self.left == self.right == None:
return None
if self.left == None:
return self.right
if self.right == None:
return self.left
child = self.left
grandchild = child.right
if grandchild:
while grandchild.right:
child = grandchild
grandchild = child.right
self.value = grandchild.value
child.right = grandchild.left
else:
self.left = child.left
self.value = child.value
return self
class BinaryTree:
def __init__(self):
"""Create empty binary tree"""
self.root = None
def add(self, value):
"""Insert value into proper location in Binary Tree"""
if self.root is None:
self.root = BinaryNode(value)
else:
self.root.add(value)
def contains(self, target):
"""Check whether BST contains target value"""
node = self.root
while node:
if target == node.value:
return True
if target < node.value:
node = node.left
else:
node = node.right
return False
def remove(self, value):
"""Remove value from tree"""
if self.root:
self.root = self.removeFromParent(self.root, value)
def removeFromParent(self, parent, value):
"""remove value from tree rooted at parent"""
if parent is None:
return None
if value == parent.value:
return parent.delete()
elif value < parent.value:
parent.left = self.removeFromParent(parent.left, value)
else:
parent.right = self.removeFromParent(parent.right, value)
return parent
可在此处找到:https://github.com/heineman/python-algorithms/blob/master/1.%20Log%20N%20Behavior/bst.py#L2
我的问题如下。鉴于我想从中删除节点14:
我希望它能找到左边nodetree中的最大值,在本例中是13.然后我希望值为14的节点现在包含值13,并且应该从节点树中删除值为13的节点
但是,我不知道上面复制的代码是如何做到的。首先,我们将值14传递给remove函数。我们将根节点(8)和值14传递给remove_from_parent函数。由于该值大于父值,我们调用remove_from_parent递归传入右子(10)和值14.由于该值再次大于父值,我们再次调用remove_from_parent传入右子(14)和值14.现在我们有一个相等的匹配,所以我们调用parent.delete,它返回左节点(13)。所以现在callstack有三个递归迭代,在最后一个序列中它返回带有13的节点,在前一个序列中它返回带有10的节点,而初始序列返回带有8的节点。因此,因为初始调用执行了以下操作:@root = remove_from_parent (@root,value),我认为@root现在是值为13的节点,毕竟我们正在做任务&#34; =&#34;所以递归中的最后一次调用会覆盖其他调用。但这里似乎有些不对劲。因为带有13的节点不是根节点。值为8的节点是根。我错过了什么?
答案 0 :(得分:0)
在最后一步(当您到达节点14时),您将返回“delete”的输出,该输出将其中一个子节点替换为要删除的节点并返回其父节点。这意味着,节点10将被返回,并最终返回它自己的父节点(即节点8)。
UPDATE(在仔细查看有点令人困惑的命名之后):“删除”的作用是用一个子节点(在本例中为13)替换节点值(在您的情况下为14)。然后它返回修改后的节点(13)。现在请记住,此调用是从上一次迭代中进行的,返回的结果将只是父节点之一子节点的新值(将返回到上一次调用)。最终你将进入以root开头的第一个电话。
命名中的混淆(对我来说)来自“父”这个词,它实际上意味着节点本身。
更新2:removeFromParent执行以下操作之一:
如果调用它的节点为None,则返回None。
如果调用它的节点具有要删除的值,则返回“delete”的结果,如果该节点没有子节点则返回None,否则返回带有该节点的节点值移动(节点值用其中一个分支代替)。
否则,它会更改节点的一个子节点并返回节点。
当你到达节点10时,这正是将要发生的事情:它返回节点10,带有修改后的左分支(它将存储由“delete”返回的结果,即13)。其余的只是冒泡。
答案 1 :(得分:0)
此代码实现的算法实际上需要更复杂一些。只有对removeFromParent
的最后一次递归调用才能返回除传递它之前的parent
值以外的任何内容。只有当parent
是要返回的值时它才会返回,并且是一个叶子节点。
如果您使用迭代算法,可能更容易理解:
def remove(self, value):
if self.root and self.root.value == value: # special case for removing the root
self.root = self.root.delete()
return
else: # general case, removing a child node of some parent
parent = self.root
while parent:
if value < parent.value:
child = parent.left
if child and child.value == value:
parent.left = child.delete()
return
parent = child
else:
child = parent.right
if child and child.value == value:
parent.right = child.delete()
return
parent = child
# if we get here, value was never found, perhaps raise an exception?