Red Black Tree insertion operation keeps on crashing
我正在尝试实现Red Black Tree,但我自己无法对其进行编码,因此我在搜索它是用C编写的代码,并在github上找到了下面经过分析的代码,它非常简单明了,所以我做了稍作修改(只是重命名了几个变量并添加了一个菜单),当我尝试运行它时,在尝试旋转树时遇到了一个问题。插入工作正常,直到树变得不平衡为止,特别是当叔叔变成"黑色"时,我的程序无法旋转树,并且崩溃了。因此,让我向您解释程序的流程:每当我们插入一个新节点时,都会调用一个名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | #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("\ Here 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\ "); printf("2.) exit\ "); 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)) != '\ ') {} break; } getch(); } } |
在第53行带有警告的情况下进行编译:
1 2 | else if(par = par->parent->left) par->parent->left = child; |
您正在分配,要比较:
1 2 | else if(par == par->parent->left) par->parent->left = child; |
主要问题
如前所述,第53行
else if(par = par->parent->left)
必须为
1 | else if(par == par->parent->left) |
insertFixup中的算法不正确,例如,先插入数据3,然后插入2,然后插入1,则会导致崩溃,我在互联网上看到一个相同的定义,可能您理解了,但不幸的是您的源已被窃听。该定义有效:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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 *的签名错误,main返回一个int
如果用户未输入int,则您的scanf行160不会设置字符,并且您可以测试从未初始化的值。始终检查scanf的返回值,例如:与:
之后的代码兼容
1 2 |
在
1
2
设置了
c但从未使用过,例如,如果达到EOF,则最糟糕的情况是因为输入已重定向到文件上,因此您将循环播放而不会结束。例如do
第10行:
1 int count = 0;
定义一个从未使用过的全局变量,您可以删除该行
要检查我的建议,我添加了该功能以显示树:
1 2 3 4 5 6 7 |
我修改了您的main以便能够显示树:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | int main() { int men, c, data; node *root = NULL; while (1) { fputs("\ " "1.) Insert\ " "2.) exit\ " "3.) Display tree\ " "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('\ '); break; default: puts("Invalid choice!"); while ((c = fgetc(stdin)) != '\ ') if (c == EOF) exit(0); break; } } } |
编译和执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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$ |