【发布时间】:2019-09-07 02:13:03
【问题描述】:
我正在实现一棵红黑树。目前卡在树的旋转上。当我旋转并分配新的左/右孩子时,我崩溃并燃烧。我学会在二叉树上进行左右旋转的方式是这样的(在 C++ 中):
void right_rotation(node *&root)
{
auto *temp = root->left;
root->left = temp->right;
temp->right = root;
root = temp;
}
这适用于 AVL 树。
这是 RB 树。我将尝试发布重现此内容所需的最低限度
#include <stdio.h>
struct foo
{
int key;
foo *parent;
foo *left;
foo *right;
int rb; // 0 black, 1 red
foo(int k, foo *p, foo *l, foo *r, int _rb) : key(k), parent(p), left(l), right(r), rb(_rb) {}
};
class rbtree
{
public:
foo *root{};
void insert(int key)
{
if (root != nullptr)
insert(root, root, key);
else
root = new foo(key, nullptr, nullptr, nullptr, 0);
}
void insert(foo *&node, foo *&parent, int key)
{
if (!node) {
node = new foo(key, parent, nullptr, nullptr, 1);
rebalance(node);
} else if (key <= node->key) {
insert(node->left, node, key);
} else {
insert(node->right, node, key);
}
}
void rebalance(foo *&node)
{
if (!node)
return;
if (root == node) {
root->rb = 0;
return;
}
if (node->rb == 1 && node->parent->rb == 1) {
auto *grand_p = node->parent->parent;
foo *aunt;
if (grand_p->left != node->parent)
aunt = grand_p->left;
else
aunt = grand_p->right;
if (!aunt || aunt->rb == 0)
rotate(node, grand_p);
else
color_flip(node);
}
// if there is no parent to the root
if (!node->parent)
root = node;
rebalance(node->parent);
}
void rotate(foo *&node, foo *&grand_parent)
{
if (grand_parent->right->left == node) {
right_left_rot(node);
} // else the rest is not critical
}
void right_rot(foo *&root)
{
auto *grand_p = root->parent;
auto *tmp = root->left;
if (!tmp->left)
printf("\nI am about to crash");
root->left = tmp->right; // segfault here
// the rest of the rotation logic
tmp->right = root;
root->parent = tmp;
if (root->left)
root->left->parent = root;
if (grand_p) {
if (root == grand_p->left)
grand_p->left = tmp;
else if (root == grand_p->right)
grand_p->right = tmp;
}
tmp->parent = grand_p;
}
void right_left_rot(foo *&node)
{
right_rot(node->parent);
// rest not important
}
void color_flip(foo *&node)
{
node->parent->parent->rb = 1;
node->parent->parent->left->rb = 0;
node->parent->parent->right->rb = 0;
if (root->rb != 0)
root->rb = 0;
}
};
int main()
{
rbtree rbt;
rbt.insert(3);
printf("\n%s%d", "Added successfully ", 3);
rbt.insert(1);
printf("\n%s%d", "Added successfully ", 1);
rbt.insert(5);
printf("\n%s%d", "Added successfully ", 5);
rbt.insert(7);
printf("\n%s%d", "Added successfully ", 7);
rbt.insert(6);
printf("\n%s%d", "Added successfully ", 6);
return 0;
}
据我所知,tmp->left 是nullptr,因此当我将其分配给root->left 时,出现段错误是正常的。我该如何克服这个问题并执行此步骤而不终止?
我搜索过 SO 和其他互联网角落,发现人们使用这种方法,他们没有抱怨这个段错误。
如果我检查if (tmp->right) root->left = tmp->right;,那么代码不会被执行,我会跳过一个关键的算法步骤。通过这个if 语句,我得到了一棵树,其中一些节点指向自己,它变得非常混乱。
示例案例
为了得到这种情况,我插入 3(root)->1(go left of 3)->5(go right of 3)->7(go right of 5)->6(go left of 7) .必须在 5->7->6 处进行平衡。逻辑是进行左右旋转。在正确的轮换中,这种情况正在发生
【问题讨论】:
-
对于这类事情,我发现纸上调试很有帮助。
-
在失败步骤之前打印你的树,检查你的假设是否正确
-
如果没有一个完整的例子让我们自己看到崩溃,我认为我们无法为您提供太多帮助(另请参阅Minimal, Complete, and Verifiable example)
-
如果您在指定位置遇到段错误,则 tmp 为空)并且 tmp->right 无意义)。尝试将空节点旋转到任何其他节点的父位置表明您在确定您将哪个节点视为根节点以调用旋转函数的逻辑中存在错误。除此之外,如上所述,我们需要一个 MCV 示例。
-
很抱歉回复晚了,也很抱歉没有提供足够的信息。我希望编辑更清楚。
标签: c++ red-black-tree red-black-tree-insertion