我正在尝试构建RBT,特别是现在我正在尝试实现RBT的删除操作,这非常复杂。我理解第一个想法是替换我们要删除的节点,如果它有两个非叶子节点,其后继节点,最多可能有一个非叶子节点。然后删除总是减少删除最多只有一个孩子的节点(如BST删除操作)。
我试图在Wiki's article上关注此问题,但在一段时间后我仍然很困惑,试图理解所有案例等等。在文章中,他们代表了具有真实节点的无叶子女孩,但在我的情况下,我只是用None
代表无叶儿童,所以这也可能是我的混淆之源。
所以,从现在开始假设我们已经将节点替换为其继承者,最终如果它最初有2个非叶子节点。
我理解
如果节点n
为红色,我们可以简单地将其删除,而不会有违反任何属性的风险。
如果节点n
为黑色,则故事不同。
2.1简单的情况是唯一可能的非叶子孩子是红色的。在这种情况下,我们只需将n
替换为其子项,并将子项的颜色更改为黑色。
2.2。困难的情况是n
及其可能的孩子都是黑人。但显然和令人惊讶的是,只有当n
的两个孩子都是空叶节点时才会发生这种情况,在我看来,它们只是None
。这是为什么?由于我们知道n
最多只有一个孩子,如果那个孩子不是零叶节点,并且我们知道它是黑色的,那么包含它的子树上的黑色高度将大于黑色 - 仅包含空叶节点的子树的高度。
如果到目前为止我的所有推理都是正确的,那么我会有一个问题。在Wiki的文章中,有以下功能:
void delete_one_child(struct node *n)
{
/*
* Precondition: n has at most one non-null child.
*/
struct node *child = is_leaf(n->right) ? n->left : n->right;
replace_node(n, child);
if (n->color == BLACK) {
if (child->color == RED)
child->color = BLACK;
else
delete_case1(child);
}
free(n);
}
我试图了解这个功能究竟要完成什么。因此,它将n
替换为其子项,即为了删除n
。因此,它检查n
的颜色是否为黑色,因为如果它是红色的,我们只是谈论我们上面谈到的第一个简单情况。如果它是黑色的并且它的孩子是红色的,那么我们正在讨论2.1的情况。否则,我们去所有其他"复杂"例。
我不明白的是该代码下的评论:
注意:如果
N
是一个空叶并且我们不想将空叶表示为实际节点对象,我们可以通过首先在其父节点上调用delete_case1()
来修改该算法(我们删除的节点,上面代码中的n
并在之后删除。如果父级是黑色的(红色是微不足道的),我们这样做,所以它的行为方式与空叶子相同(有时称为“幻像'叶子”)。
我们可以安全地删除它,因为
n
将在所有操作后保持一个叶子,如上所示。此外,案例2和案例3中的兄弟测试需要更新,因为兄弟姐妹不会将孩子表示为对象。
1)我的理解是我需要遵循这个建议,但我并没有完全理解它。在我的情况下,我需要先调用delete_case1(n)
(即n
,我要删除的节点),并在所有调用结束时删除节点" delete_casesX&# 34; s,仅当n
为黑色时才这样做,即仅在检查后
if (n->color == BLACK) {
// Should I call delete_case1() on n here
// that is, delete_case1(n) ?
2)我的第二个问题是我不完全理解为什么n
表现得像零叶一样。
3)这里N
是什么? n
或其孩子?
4)显然n
必须在所有操作后保持一片叶子,但为什么呢? (也许这个问题与问题2有关)。
我已经实现了插入操作,并且它比删除更容易。我想我也遵循了Wiki的插入文章,当叶子只是空值或非空格时也可以使用。
请您按照Wiki的文章引导我了解如何实施此RBT?我知道这是一个非常复杂的问题,答案更复杂,但任何帮助都表示赞赏。如果有什么不清楚,请问。