红黑树插入操作一直崩溃
Red Black Tree insertion operation keeps on crashing
我试图实现红黑树,但无法自己编写代码,所以我搜索了用 C 编写的代码,并在 [=38= 上找到了以下代码] 我对其进行了分析,它非常简单明了,所以我做了一些修改(只是重命名了几个变量并添加了一个菜单),当我尝试 运行 它时,我在尝试旋转时遇到了问题树。插入工作正常,直到树变得不平衡,特别是当叔叔变成 "Black" 我的程序无法旋转树并且它只是崩溃。因此,让我向您解释程序的流程:每当我们插入一个新节点时,都会调用一个名为 insert
的函数,在成功插入后,它会调用另一个名为 insertfixup
的函数来检查 Red 的任何属性黑树已被违反,如果是,则它根据问题节点的叔叔是 RED 还是 [=20 来旋转树=]BLACK如果大叔是Red那么可以正常工作,但是很快当叔叔变成 Black 然后它就崩溃了。有人可以检查我在下面给出的代码并指出到底是什么导致了问题,我怀疑它与指针有关但无法弄清楚实际发生了什么,
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
typedef struct RB_Tree {
struct RB_Tree *left, *right, *parent;
int info;
char color;
} node;
int count = 0;
void left_rotate(node **root, node *par) {
node *child = par->right;
par->right = child->left;
if (child->left!=NULL)
child->left->parent = par;
child->parent = par->parent;
if (par->parent == NULL)
(*root) = child;
else
if (par == par->parent->left)
par->parent->left = child;
else
par->parent->right = child;
child->left = par;
par->parent = child;
}
void right_rotate(node **root, node *par) {
node *child = par->left;
par->left = child->right;
if (child->right!=NULL)
child->right->parent = par;
child->parent = par->parent;
if (par->parent == NULL)
(*root) = child;
else
if (par = par->parent->left)
par->parent->left = child;
else
par->parent->right = child;
child->right = par;
par->parent = child;
}
void insertFixup(node **root, node *new) {
while (new != *root && new->parent->color == 'R') {
node *uncle;
//Find uncle and store uncle in "uncle" variable!
if (new->parent == new->parent->parent->left) {
uncle = new->parent->parent->right;
} else {
uncle = new->parent->parent->left;
}
if (uncle == NULL || uncle->color == 'B') {
if (new->parent == new->parent->parent->left && new == new->parent->left) {
printf("Inside ll case before rot");
char col = new->parent->color;
new->parent->color = new->parent->parent->color;
new->parent->parent->color = col;
right_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->right && new == new->parent->right) {
char col = new->parent->color;
new->parent->color = new->parent->parent->color;
new->parent->parent->color = col;
left_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->left && new == new->parent->right) {
char col = new->color;
new->color = new->parent->parent->color;
new->parent->parent->color = col;
//printf("\nHere we are in the left right!");
left_rotate(root, new->parent);
right_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->right && new == new->parent->left) {
char col = new->color;
new->color = new->parent->parent->color;
new->parent->parent->color = col;
right_rotate(root, new->parent);
left_rotate(root, new->parent->parent);
}
}
if (uncle) {
if (uncle->color == 'R') {
uncle->color = 'B';
new->parent->color = 'B';
new->parent->parent->color = 'R';
new = new->parent->parent;
}
}
}
(*root)->color = 'B';
}
void insert(node **root, int data) {
node *new = (node*)malloc(sizeof(node));
new->info = data;
new->parent = new->left = new->right = NULL;
if (*root == NULL) {
(*root) = new;
new->color = 'B';
} else {
node *par;
node *temp = (*root);
while (temp) {
par = temp;
if(new->info > temp->info)
temp = temp->right;
else
temp = temp->left;
}
new->parent = par;
if (par->info > new->info)
par->left = new;
else
par->right = new;
new->color = 'R';
insertFixup(root, new);
}
}
void main() {
int men, c, data;
node *root = NULL;
while (1) {
system("cls");
printf("1.) Insert\n");
printf("2.) exit\n");
printf("Enter your choice : ");
scanf("%d", &men);
switch (men) {
case 1:
printf("Enter data : ");
scanf("%d", &data);
insert(&root, data);
printf("%d successfully added!", data);
break;
case 2:
exit(0);
default:
printf("Invalid choice!");
while ((c = fgetc(stdin)) != '\n') {}
break;
}
getch();
}
}
编译时出现警告,第 53 行:
else if(par = par->parent->left)
par->parent->left = child;
您正在分配,您要比较:
else if(par == par->parent->left)
par->parent->left = child;
主要问题
第53行已经说过
else if(par = par->parent->left)
必须是
else if(par == par->parent->left)
insertFixup中的算法不正确,例如插入数据 3 然后 2 然后 1 会导致崩溃,我在网上看到一个相同的定义,可能是你知道了,但不幸的是你的来源被窃听了。该定义有效:
void insertFixup(node **root, node *new) {
while (new != *root && new->parent->color == 'R') {
if (new->parent == new->parent->parent->left) {
if (new->parent->parent->right && new->parent->parent->right->color == 'R') {
new->parent->color = 'B';
new->parent->parent->right->color = 'B';
new->parent->parent->color = 'R';
new = new->parent->parent;
}
else {
if (new == new->parent->right) {
new = new->parent;
left_rotate(root, new);
}
new->parent->color = 'B';
new->parent->parent->color = 'R';
right_rotate(root, new->parent->parent);
}
}
else {
if (new->parent->parent->left && new->parent->parent->left->color == 'R') {
new->parent->color = 'B';
new->parent->parent->left->color = 'B';
new->parent->parent->color = 'R';
new = new->parent->parent;
}
else {
if (new == new->parent->left) {
new = new->parent;
right_rotate(root, new);
}
new->parent->color = 'B';
new->parent->parent->color = 'R';
left_rotate(root, new->parent->parent);
}
}
}
(*root)->color = 'B';
}
其他问题
*main*的签名错误,mainreturns an int
如果用户没有输入一个 int 你的 scanf 第 160 行没有设置 men 你可以测试一个从未初始化的值。 始终 检查 scanf 的 return 值,例如与 :
之后的代码兼容
if (scanf("%d", &men) != 1)
men = -1;
在
while ((c = fgetc(stdin)) != '\n') {}
c 已设置但从未使用过,最糟糕的是如果你达到 EOF 例如因为输入被重定向到一个文件你会循环没有结束。例如做
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
exit(0);
第 10 行:
int count = 0;
定义一个从未使用过的全局变量,您可以删除该行
为了检查我的建议,我添加了显示树的功能:
void display(node * x){
if (x) {
display(x->left);
printf("%d ", x->info);
display(x->right);
}
}
并且我修改了您的 main 以便能够显示树 :
int main()
{
int men, c, data;
node *root = NULL;
while (1) {
fputs("\n"
"1.) Insert\n"
"2.) exit\n"
"3.) Display tree\n"
"Enter your choice : ",
stdout);
if (scanf("%d", &men) != 1)
men = -1;
switch (men) {
case 1:
printf("Enter data : ");
scanf("%d", &data);
insert(&root, data);
printf("%d successfully added!", data);
break;
case 2:
exit(0);
case 3:
display(root);
putchar('\n');
break;
default:
puts("Invalid choice!");
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
exit(0);
break;
}
}
}
编译与执行:
bruno@bruno-XPS-8300:/tmp/t$ gcc -Wall -Wextra t.c
bruno@bruno-XPS-8300:/tmp/t$ ./a.out
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 3
3 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 2
2 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 1
1 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 3
1 2 3
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 5
5 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 4
4 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 3
1 2 3 4 5
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 2
bruno@bruno-XPS-8300:/tmp/t$
我试图实现红黑树,但无法自己编写代码,所以我搜索了用 C 编写的代码,并在 [=38= 上找到了以下代码] 我对其进行了分析,它非常简单明了,所以我做了一些修改(只是重命名了几个变量并添加了一个菜单),当我尝试 运行 它时,我在尝试旋转时遇到了问题树。插入工作正常,直到树变得不平衡,特别是当叔叔变成 "Black" 我的程序无法旋转树并且它只是崩溃。因此,让我向您解释程序的流程:每当我们插入一个新节点时,都会调用一个名为 insert
的函数,在成功插入后,它会调用另一个名为 insertfixup
的函数来检查 Red 的任何属性黑树已被违反,如果是,则它根据问题节点的叔叔是 RED 还是 [=20 来旋转树=]BLACK如果大叔是Red那么可以正常工作,但是很快当叔叔变成 Black 然后它就崩溃了。有人可以检查我在下面给出的代码并指出到底是什么导致了问题,我怀疑它与指针有关但无法弄清楚实际发生了什么,
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
typedef struct RB_Tree {
struct RB_Tree *left, *right, *parent;
int info;
char color;
} node;
int count = 0;
void left_rotate(node **root, node *par) {
node *child = par->right;
par->right = child->left;
if (child->left!=NULL)
child->left->parent = par;
child->parent = par->parent;
if (par->parent == NULL)
(*root) = child;
else
if (par == par->parent->left)
par->parent->left = child;
else
par->parent->right = child;
child->left = par;
par->parent = child;
}
void right_rotate(node **root, node *par) {
node *child = par->left;
par->left = child->right;
if (child->right!=NULL)
child->right->parent = par;
child->parent = par->parent;
if (par->parent == NULL)
(*root) = child;
else
if (par = par->parent->left)
par->parent->left = child;
else
par->parent->right = child;
child->right = par;
par->parent = child;
}
void insertFixup(node **root, node *new) {
while (new != *root && new->parent->color == 'R') {
node *uncle;
//Find uncle and store uncle in "uncle" variable!
if (new->parent == new->parent->parent->left) {
uncle = new->parent->parent->right;
} else {
uncle = new->parent->parent->left;
}
if (uncle == NULL || uncle->color == 'B') {
if (new->parent == new->parent->parent->left && new == new->parent->left) {
printf("Inside ll case before rot");
char col = new->parent->color;
new->parent->color = new->parent->parent->color;
new->parent->parent->color = col;
right_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->right && new == new->parent->right) {
char col = new->parent->color;
new->parent->color = new->parent->parent->color;
new->parent->parent->color = col;
left_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->left && new == new->parent->right) {
char col = new->color;
new->color = new->parent->parent->color;
new->parent->parent->color = col;
//printf("\nHere we are in the left right!");
left_rotate(root, new->parent);
right_rotate(root, new->parent->parent);
}
if (new->parent == new->parent->parent->right && new == new->parent->left) {
char col = new->color;
new->color = new->parent->parent->color;
new->parent->parent->color = col;
right_rotate(root, new->parent);
left_rotate(root, new->parent->parent);
}
}
if (uncle) {
if (uncle->color == 'R') {
uncle->color = 'B';
new->parent->color = 'B';
new->parent->parent->color = 'R';
new = new->parent->parent;
}
}
}
(*root)->color = 'B';
}
void insert(node **root, int data) {
node *new = (node*)malloc(sizeof(node));
new->info = data;
new->parent = new->left = new->right = NULL;
if (*root == NULL) {
(*root) = new;
new->color = 'B';
} else {
node *par;
node *temp = (*root);
while (temp) {
par = temp;
if(new->info > temp->info)
temp = temp->right;
else
temp = temp->left;
}
new->parent = par;
if (par->info > new->info)
par->left = new;
else
par->right = new;
new->color = 'R';
insertFixup(root, new);
}
}
void main() {
int men, c, data;
node *root = NULL;
while (1) {
system("cls");
printf("1.) Insert\n");
printf("2.) exit\n");
printf("Enter your choice : ");
scanf("%d", &men);
switch (men) {
case 1:
printf("Enter data : ");
scanf("%d", &data);
insert(&root, data);
printf("%d successfully added!", data);
break;
case 2:
exit(0);
default:
printf("Invalid choice!");
while ((c = fgetc(stdin)) != '\n') {}
break;
}
getch();
}
}
编译时出现警告,第 53 行:
else if(par = par->parent->left)
par->parent->left = child;
您正在分配,您要比较:
else if(par == par->parent->left)
par->parent->left = child;
主要问题
第53行已经说过
else if(par = par->parent->left)
必须是
else if(par == par->parent->left)
insertFixup中的算法不正确,例如插入数据 3 然后 2 然后 1 会导致崩溃,我在网上看到一个相同的定义,可能是你知道了,但不幸的是你的来源被窃听了。该定义有效:
void insertFixup(node **root, node *new) {
while (new != *root && new->parent->color == 'R') {
if (new->parent == new->parent->parent->left) {
if (new->parent->parent->right && new->parent->parent->right->color == 'R') {
new->parent->color = 'B';
new->parent->parent->right->color = 'B';
new->parent->parent->color = 'R';
new = new->parent->parent;
}
else {
if (new == new->parent->right) {
new = new->parent;
left_rotate(root, new);
}
new->parent->color = 'B';
new->parent->parent->color = 'R';
right_rotate(root, new->parent->parent);
}
}
else {
if (new->parent->parent->left && new->parent->parent->left->color == 'R') {
new->parent->color = 'B';
new->parent->parent->left->color = 'B';
new->parent->parent->color = 'R';
new = new->parent->parent;
}
else {
if (new == new->parent->left) {
new = new->parent;
right_rotate(root, new);
}
new->parent->color = 'B';
new->parent->parent->color = 'R';
left_rotate(root, new->parent->parent);
}
}
}
(*root)->color = 'B';
}
其他问题
*main*的签名错误,mainreturns an int
如果用户没有输入一个 int 你的 scanf 第 160 行没有设置 men 你可以测试一个从未初始化的值。 始终 检查 scanf 的 return 值,例如与 :
之后的代码兼容if (scanf("%d", &men) != 1)
men = -1;
在
while ((c = fgetc(stdin)) != '\n') {}
c 已设置但从未使用过,最糟糕的是如果你达到 EOF 例如因为输入被重定向到一个文件你会循环没有结束。例如做
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
exit(0);
第 10 行:
int count = 0;
定义一个从未使用过的全局变量,您可以删除该行
为了检查我的建议,我添加了显示树的功能:
void display(node * x){
if (x) {
display(x->left);
printf("%d ", x->info);
display(x->right);
}
}
并且我修改了您的 main 以便能够显示树 :
int main()
{
int men, c, data;
node *root = NULL;
while (1) {
fputs("\n"
"1.) Insert\n"
"2.) exit\n"
"3.) Display tree\n"
"Enter your choice : ",
stdout);
if (scanf("%d", &men) != 1)
men = -1;
switch (men) {
case 1:
printf("Enter data : ");
scanf("%d", &data);
insert(&root, data);
printf("%d successfully added!", data);
break;
case 2:
exit(0);
case 3:
display(root);
putchar('\n');
break;
default:
puts("Invalid choice!");
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
exit(0);
break;
}
}
}
编译与执行:
bruno@bruno-XPS-8300:/tmp/t$ gcc -Wall -Wextra t.c
bruno@bruno-XPS-8300:/tmp/t$ ./a.out
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 3
3 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 2
2 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 1
1 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 3
1 2 3
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 5
5 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 1
Enter data : 4
4 successfully added!
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 3
1 2 3 4 5
1.) Insert
2.) exit
3.) Display tree
Enter your choice : 2
bruno@bruno-XPS-8300:/tmp/t$