删除具有两个子节点的节点时,可以选择其有序后继节点或有序前驱节点。在这种情况下,它在左子树(即其左子树的最右边的孩子)中查找最大值,这意味着它正在查找节点的有序前驱节点。
找到替换节点后,实际上并没有删除要删除的节点。相反,您从后继节点获取值并将该值存储在要删除的节点中。然后,您删除后继节点。这样做可以保留二叉搜索树属性,因为您可以确定您选择的节点的值将低于原始节点左子树中所有子节点的值,并且大于该值原始节点的右子树中的所有子节点。
编辑
在阅读了你的问题之后,我想我已经找到了问题所在。
通常,除了delete
函数之外,您还有一个replace
替换相关节点的函数。我认为您需要更改这行代码:
FindParent(largestValue).Right <- 0
至:
FindParent(largestValue).Right <- largestValue.Left
如果largestValue
节点没有左孩子,你只需得到null
or 0
。如果它确实有一个左孩子,则该孩子将成为该largestValue
节点的替代品。所以你是对的;该代码没有考虑largestValue
节点可能有左孩子的情况。
另一个编辑
由于您只发布了一个片段,我不确定代码的上下文是什么。但是发布的片段似乎确实存在您建议的问题(替换错误的节点)。通常,有三种情况,但我注意到您的代码段中的评论说//Case 4
(所以也许还有其他上下文)。
早些时候,我提到了delete
通常带有replace
. 因此,如果找到该largestValue
节点,则根据两种简单情况(没有孩子的节点和有一个孩子的节点)将其删除。因此,如果您正在查看用于删除具有两个孩子的节点的伪代码,您将执行以下操作:
get largestValue from nodeToRemove.Left
nodeToRemove.Value <- largestValue.Value
//now replace largestValue with largestValue.Left
if largestValue = largestValue.Parent.Left then
largestValue.Parent.Left <- largestValue.Left //is largestValue a left child?
else //largestValue must be a right child
largestValue.Parent.Right <- largestValue.Left
if largestValue.Left is not null then
largestValue.Left.Parent <- largestValue.Parent
我觉得很奇怪,一本数据结构和算法的书会遗漏这部分,所以我倾向于认为这本书进一步将删除分成几个案例(因为有三个标准案例),以便更容易理解。
为了证明上述代码有效,请考虑以下树:
8
/ \
7 9
假设您要删除8
. 您尝试largestValue
从nodeToRemove.Left
. 这给了你,7
因为左子树只有一个孩子。
然后你做:
nodeToRemove.Value <- largestValue.Value
意思是:
8.value <- 7.Value
或者
8.Value <- 7
所以现在你的树看起来像这样:
7
/ \
7 9
您需要摆脱替换节点,因此您将替换largestValue
为largestValue.Left
(即null
)。所以首先你要知道什么样的孩子7
是:
if largestValue = largestValue.Parent.Left then
意思是:
if 7 = 7.Parent.Left then
或者:
if 7 = 8.Left then
由于7
是8
的左孩子,需要8.Left
用7.Right
( largestValue.Parent.Left <- largestValue.Left
) 代替。由于7
没有孩子,7.Left
因此为空。所以largestValue.Parent.Left
被分配给 null (这有效地删除了它的左孩子)。所以这意味着你最终得到以下树:
7
\
9