确保从根到树叶节点的每条路径都具有相同数量的黑色节点 (C)
Ensure every path from root to a tree leaf node has the same number of black nodes ( C )
我正在为大学目的实现一棵红黑树,我坚持 属性 从根到叶的每条路径都应该有相同数量的黑色节点。
我已经插入了所有需要的功能:fixup, rotation, insertion
...但我不知道如何处理这个功能。我在想类似的东西:
void checkNuberBlackNodes(struct node* root) {
if( numberBlackNodes(root->right) > numberBlackNodes(root->left) {
leftRotate(root);
colorize(root);
}
else if( numberBlackNodes(root->right) < numberBlackNodes(root->left) {
rightRotate(root);
colorize(root);
}
else return; //no violation, same number of black nodes
}
想法是 insert
一个节点,fix up
违规,然后 checkNumberBlackNodes
在插入的新节点上(或从根)。
我不知道如何处理这个过程,所有以前的功能都很容易实现,这是......我不知道如何开始。
编辑:我有一个新想法:
void checkNuberBlackNodes(struct node* root) {
int diff = height(root->right) - height(root->left);
if ( diff >=2 ) //if the tree is too deep
{
leftRotate(root->right);
checkNuberBlackNodes(root->right);
return;
}
else if ( diff <= -2 ) //specular case
{
rightRotate(root->left);
checkNuberBlackNodes(root->left);
return;
}
else if( blackHeight(root->right) > blackHeight(root->left) {
colorize(root->right);
checkNuberBlackNodes(root->right);
return;
}
else if( blackHeight(root->right) < blackHeight(root->left) {
colorize(root->left);
checkNuberBlackNodes(root->left);
return;
}
else return; //No violation
}
blackHeight
是从节点到叶子的路径中黑色节点的数量;
如果向Red-Black树中插入一个新节点,则该节点始终是末尾的叶节点。
而且总是红色。
一般
(1) 插入一个节点可能会违反“没有连续的红色节点”规则,修正将在根的方向。最多需要 2 次旋转和 3 * O(h/2) 次重新着色,其中 h 是树的高度。如果插入节点的parent为黑色,则无需修正。
(2) 删除节点可能会违反“从根向下每条路径的黑色节点数相同”的规则。同样,修复发生在根目录下。最多需要 3 次旋转和 O(h) 次重新着色,其中 h 是树的高度。
如果要删除的节点是没有children的根节点,则删除它。
如果要删除的Node有两个children,找到直接后继(向右child然后一直向左),交换Node和后继Node(但PRESERVE原来的节点的颜色)。后继节点将始终是 0-children 或 1-child 节点。
现在你需要删除原来的节点但是在继承者的位置。您转到接下来的两个案例。
如果删除的节点是叶子节点,并且是红色的,不需要修复,删除节点
如果要删除的节点有一个child,是黑色,child是红色,删除节点,将节点替换为child,重新着色child 为黑色。
那么这留下了什么?
它留下一个黑色节点是叶子节点,没有children,困难的情况。
删除它会违反“从根向下每条路径的黑色节点数都相同”的规则。
删除节点后,parent 节点现在在树的一侧有黑色路径计数错误。基本上删除是一个 two-prong 策略:
a) 您检查 parent 节点、兄弟节点和兄弟节点 children 的节点,看看是否有红色节点。如果是的话,你可以使用旋转和重新着色来改变它,所以删除边上的黑洞会被重新填充,修复树。
b) 如果所有节点(或 NULL 节点)都是黑色的,那么你将兄弟节点设为红色,parent 节点现在被认为是修复树的点。你已经使树的两边都变得同样糟糕,现在修复点高了 1 级。您返回到步骤 a),因为有“parent”、“sibling”和“sibling children”的新定义。
c) 有可能有一棵 red-black 树完全是黑色的。如果到达根并且没有遇到红色节点,会发生什么情况?然后它现在是一棵 red-black 树。实际上,changing siblings 在每条树路径中引入了 1 个红色节点,将黑色树的高度统一降低 1。
我正在为大学目的实现一棵红黑树,我坚持 属性 从根到叶的每条路径都应该有相同数量的黑色节点。
我已经插入了所有需要的功能:fixup, rotation, insertion
...但我不知道如何处理这个功能。我在想类似的东西:
void checkNuberBlackNodes(struct node* root) {
if( numberBlackNodes(root->right) > numberBlackNodes(root->left) {
leftRotate(root);
colorize(root);
}
else if( numberBlackNodes(root->right) < numberBlackNodes(root->left) {
rightRotate(root);
colorize(root);
}
else return; //no violation, same number of black nodes
}
想法是 insert
一个节点,fix up
违规,然后 checkNumberBlackNodes
在插入的新节点上(或从根)。
我不知道如何处理这个过程,所有以前的功能都很容易实现,这是......我不知道如何开始。
编辑:我有一个新想法:
void checkNuberBlackNodes(struct node* root) {
int diff = height(root->right) - height(root->left);
if ( diff >=2 ) //if the tree is too deep
{
leftRotate(root->right);
checkNuberBlackNodes(root->right);
return;
}
else if ( diff <= -2 ) //specular case
{
rightRotate(root->left);
checkNuberBlackNodes(root->left);
return;
}
else if( blackHeight(root->right) > blackHeight(root->left) {
colorize(root->right);
checkNuberBlackNodes(root->right);
return;
}
else if( blackHeight(root->right) < blackHeight(root->left) {
colorize(root->left);
checkNuberBlackNodes(root->left);
return;
}
else return; //No violation
}
blackHeight
是从节点到叶子的路径中黑色节点的数量;
如果向Red-Black树中插入一个新节点,则该节点始终是末尾的叶节点。 而且总是红色。
一般
(1) 插入一个节点可能会违反“没有连续的红色节点”规则,修正将在根的方向。最多需要 2 次旋转和 3 * O(h/2) 次重新着色,其中 h 是树的高度。如果插入节点的parent为黑色,则无需修正。
(2) 删除节点可能会违反“从根向下每条路径的黑色节点数相同”的规则。同样,修复发生在根目录下。最多需要 3 次旋转和 O(h) 次重新着色,其中 h 是树的高度。
如果要删除的节点是没有children的根节点,则删除它。
如果要删除的Node有两个children,找到直接后继(向右child然后一直向左),交换Node和后继Node(但PRESERVE原来的节点的颜色)。后继节点将始终是 0-children 或 1-child 节点。 现在你需要删除原来的节点但是在继承者的位置。您转到接下来的两个案例。
如果删除的节点是叶子节点,并且是红色的,不需要修复,删除节点
如果要删除的节点有一个child,是黑色,child是红色,删除节点,将节点替换为child,重新着色child 为黑色。
那么这留下了什么? 它留下一个黑色节点是叶子节点,没有children,困难的情况。 删除它会违反“从根向下每条路径的黑色节点数都相同”的规则。
删除节点后,parent 节点现在在树的一侧有黑色路径计数错误。基本上删除是一个 two-prong 策略:
a) 您检查 parent 节点、兄弟节点和兄弟节点 children 的节点,看看是否有红色节点。如果是的话,你可以使用旋转和重新着色来改变它,所以删除边上的黑洞会被重新填充,修复树。 b) 如果所有节点(或 NULL 节点)都是黑色的,那么你将兄弟节点设为红色,parent 节点现在被认为是修复树的点。你已经使树的两边都变得同样糟糕,现在修复点高了 1 级。您返回到步骤 a),因为有“parent”、“sibling”和“sibling children”的新定义。 c) 有可能有一棵 red-black 树完全是黑色的。如果到达根并且没有遇到红色节点,会发生什么情况?然后它现在是一棵 red-black 树。实际上,changing siblings 在每条树路径中引入了 1 个红色节点,将黑色树的高度统一降低 1。