- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在实现一个红黑树。目前停留在树旋转上。当我旋转并分配新的左/右 child 时,我崩溃了。我学会了在二叉树上进行左旋或右旋的方法是这样的(在 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(根)->1(3 的左边)->5(3 的右边)->7(5 的右边)->6(7 的左边) .必须在 5->7->6 之间进行平衡。逻辑是进行右-左旋转。在正确的轮换中,这种情况正在发生
最佳答案
唯一需要重新平衡的是阿姨是红色的情况,在这种情况下,下一个要处理的节点将是祖 parent 节点,而不是父节点。如果阿姨是黑人,那么在单轮或双轮旋转后你就完成了。
记住,插入逻辑是:
insert as normal for any BST
set new node's color to red
LOOP:
if node is root then set node's color black and done
if node's parent's color is black then done
if node's aunt's color is red then set node's parent's and node's aunt's color to black, set node's grandparent's color to red, set node to node's grandparent and go to LOOP
if node is left child of right child or right child of left child then rotate node's parent so it is child to node otherwise set node to node's parent
set node's color to black
set node's parent's color to red
rotate so that node's parent is child to node
done
您似乎根本没有“如果节点是右 child 的左 child 或左 child 的右 child ,则旋转节点的父节点,使其成为节点的子节点,否则将节点设置为节点的父节点”步骤。
即使是最后一步,您也不会交换节点及其父节点的颜色(请注意,在此阶段,“节点”是红色违规的父节点,而不是在可选旋转之前开始的子节点)。
此外,您还有:
if (!aunt || aunt->rb == 0)
然后立即旋转,阿姨是黑色的情况是你应该颜色翻转,而不是旋转。
关于c++ - 红黑树重新平衡在树旋转时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55717250/
关于 B 树与 B+ 树,网上有一个比较经典的问题:为什么 MongoDb 使用 B 树,而 MySQL 索引使用 B+ 树? 但实际上 MongoDb 真的用的是 B 树吗?
如何将 R* Tree 实现为持久(基于磁盘)树?保存 R* 树索引或保存叶值的文件的体系结构是什么? 注意:此外,如何在这种持久性 R* 树中执行插入、更新和删除操作? 注意事项二:我已经实现了一个
目前,我正在努力用 Java 表示我用 SML 编写的 AST 树,这样我就可以随时用 Java 遍历它。 我想知道是否应该在 Java 中创建一个 Node 类,其中包含我想要表示的数据,以及一个数
我之前用过这个库http://www.cs.umd.edu/~mount/ANN/ .但是,它们不提供范围查询实现。我猜是否有一个 C++ 范围查询实现(圆形或矩形),用于查询二维数据。 谢谢。 最佳
在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择
书接上回,今天和大家一起动手来自己实现树。 相信通过前面的章节学习,大家已经明白树是什么了,今天我们主要针对二叉树,分别使用顺序存储和链式存储来实现树。 01、数组实现 我们在上一节中说过,
书节上回,我们接着聊二叉树,N叉树,以及树的存储。 01、满二叉树 如果一个二叉树,除最后一层节点外,每一层的节点数都达到最大值,即每个节点都有两个子节点,同时所有叶子节点都在最后一层,则这个
树是一种非线性数据结构,是以分支关系定义的层次结构,因此形态上和自然界中的倒挂的树很像,而数据结构中树根向上树叶向下。 什么是树? 01、定义 树是由n(n>=0)个元素节点组成的
操作系统的那棵“树” 今天从一颗 开始,我们看看如何从小树苗长成一颗苍天大树。 运转CPU CPU运转起来很简单,就是不断的从内存取值执行。 CPU没有好好运转 IO是个耗费时间的活,如果CPU在取值
我想为海洋生物学类(class)制作一个简单的系统发育树作为教育示例。我有一个具有分类等级的物种列表: Group <- c("Benthos","Benthos","Benthos","Be
我从这段代码中删除节点时遇到问题,如果我插入数字 12 并尝试删除它,它不会删除它,我尝试调试,似乎当它尝试删除时,它出错了树的。但是,如果我尝试删除它已经插入主节点的节点,它将删除它,或者我插入数字
B+ 树的叶节点链接在一起。将 B+ 树的指针结构视为有向图,它不是循环的。但是忽略指针的方向并将其视为链接在一起的无向叶节点会在图中创建循环。 在 Haskell 中,如何将叶子构造为父内部节点的子
我在 GWT 中使用树控件。我有一个自定义小部件,我将其添加为 TreeItem: Tree testTree = new Tree(); testTree.addItem(myWidget); 我想
它有点像混合树/链表结构。这是我定义结构的方式 struct node { nodeP sibling; nodeP child; nodeP parent; char
我编写了使用队列遍历树的代码,但是下面的出队函数生成错误,head = p->next 是否有问题?我不明白为什么这部分是错误的。 void Levelorder(void) { node *tmp,
例如,我想解析以下数组: var array1 = ["a.b.c.d", "a.e.f.g", "a.h", "a.i.j", "a.b.k"] 进入: var json1 = { "nod
问题 -> 给定一棵二叉树和一个和,确定该树是否具有从根到叶的路径,使得沿路径的所有值相加等于给定的和。 我的解决方案 -> public class Solution { public bo
我有一个创建 java 树的任务,它包含三列:运动名称、运动类别中的运动计数和上次更新。类似的东西显示在下面的图像上: 如您所见,有 4 种运动:水上运动、球类运动、跳伞运动和舞蹈运动。当我展开 sk
我想在 H2 数据库中实现 B+ Tree,但我想知道,B+ Tree 功能在 H2 数据库中可用吗? 最佳答案 H2 已经使用了 B+ 树(PageBtree 类)。 关于mysql - H2数据库
假设我们有 5 个字符串数组: String[] array1 = {"hello", "i", "cat"}; String[] array2 = {"hello", "i", "am"}; Str
我是一名优秀的程序员,十分优秀!