【发布时间】:2020-07-25 18:18:24
【问题描述】:
我正在尝试实现红黑树,但无法自己编写代码,所以我正在搜索它的代码,它是用 C 编写的,并在 github 上找到了以下代码,我对其进行了分析,它非常简单向前且简单,所以我做了一些修改(只是重命名了几个变量并添加了一个菜单),当我尝试运行它时,我在尝试旋转树时遇到了问题。插入工作正常,直到树变得不平衡,特别是当叔叔变成 "Black" 我的程序无法旋转树并且它只是崩溃。所以让我解释一下程序的流程:每当我们插入一个新节点时,都会调用一个名为 insert 的函数,在成功插入后,它会调用另一个名为 insertfixup 的函数,该函数检查是否有任何红黑树的属性如果违反,则根据问题节点的叔叔是 RED 还是 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();
}
}
【问题讨论】:
-
头文件:
conio.h是 windows 特定的(不可移植) 建议重写,将conio.h和相关函数替换为 c 库函数 -
关于:
void main() {尽管 Visual Studio(和其他一些相关编译器)允许void返回类型,但main()只有两个有效签名。它们是:int main( void )和int main( int argc, char* argv[] ) -
OT:关于“菜单”
printf("1.) Insert\n"); printf("2.) exit\n"); printf("Enter your choice : ");函数printf()在 CPU 周期中非常昂贵。建议:printf("%s", "1.) Insert\n" "2.) exit\n" "Enter your choice : "); -
OT:
system()cls的参数不可移植建议“\f”(换页)或 ANSI 转义序列:printf( "\1b[2J\n" ); -
OT:关于:
int count = 0;全局变量:count未在发布的代码中的任何地方使用。所以可以(并且可能应该)被淘汰
标签: c pointers data-structures tree red-black-tree