我试图编写代码来创建AVL平衡二叉树。 目的是每次插入新节点时,子树应旋转以保持(AVL)平衡。
(节点左子树中的所有值必须小于此节点值; 节点右子树中的所有值必须高于此节点值)
我刚写的代码适用于按特定顺序插入的数字,但不适用于其他代码。 例如,以下输入正常工作:
10 7 14 12 15 3 0
16 8 20 14 23 0
这个不会:
10 7 3 15 12 14 0
10 7 5 14 13 0
为什么?
#include <stdio.h>
#include <stdlib.h>
typedef enum {false, true} Boolean;
typedef enum {minus = -1, zero, plus} balance;
typedef struct nohh {
int info;
balance bal;
struct nohh *left;
struct nohh *right;
} nohh, *noh;
void PrintTree(noh p);
Boolean Insert(noh *p, int x, Boolean *alt);
void RotateLL(noh p, noh p1);
void RotateLR(noh p, noh p1);
void RotateRR(noh p, noh p1);
void RotateRL(noh p, noh p1);
int main(){
noh p = NULL;
int x;
Boolean check = false, *bol = ✓
printf("int number ('0' to exit): ");
scanf("%d", &x);
do{
check = Insert(&p, x, bol);
printf("check = %d\n", check);
printf("int number: ");
scanf("%d", &x);
}while(x != 0);
PrintTree(p);
return 0;
}
void PrintTree(noh p){
printf("%d >> bal = %d\n", p->info, p->bal);
if(p->left != NULL)
PrintTree(p->left);
if(p->right != NULL)
PrintTree(p->right);
}
Boolean Insert(noh *p, int x, Boolean *alt){
int info;
if((*p)==NULL){
*p = malloc(sizeof(nohh));
(*p)->left = (*p)->right = NULL;
(*p)->info = x;
(*p)->bal = zero;
*alt = true;
return true;
} else { /* if p isnt pointing to NULL */
info = (*p)->info;
if(x == info)
return false;
else if(x < info){ /* follow left */
Boolean res = Insert(&(*p)->left, x, alt);
if(!res)
return false;
if(*alt){ /* height increase */
noh p1;
switch((*p)->bal){
case plus:
(*p)->bal = zero; *alt = false;
break;
case zero:
(*p)->bal = minus;
break;
case minus: /* -1 -1 = -2 => not balanced!! */
p1 = (*p)->left;
if(p1->bal == minus){
/* Rotation LL */
RotateLL(*p, p1);
*alt = true;
} else if(p1->bal == plus){
/* Rotation LR */
RotateLR(*p, p1);
*alt = true;
} else {
/* Rotation LL */
RotateLL(*p, p1);
*alt = false;
}
p1->bal = zero; *alt = false;
break;
}
}
return true;
} else { /* follow right */
Boolean res = Insert(&(*p)->right, x, alt);
if(!res)
return false;
if(*alt){ /* height increase */
noh p1;
switch((*p)->bal){
case minus:
(*p)->bal = zero; *alt = false;
break;
case zero:
(*p)->bal = plus;
break;
case plus: /* 1 +1 = 2 => Not balanced! */
p1 = (*p)->right;
if(p1->bal == plus){
/* Rotation RR */
RotateRR(*p, p1);
*alt = true;
} else if(p1->bal == minus){
/* Rotation RL */
RotateRL(*p, p1);
*alt = true;
} else {
/* Rotation RR */
RotateRR(*p, p1);
*alt = false;
}
p1->bal = zero; *alt = false;
break;
}
}
return true;
}
}
}
void RotateLL(noh p, noh p1){
noh p2, aux;
p2 = p1->left;
aux = p;
p = p1;
p->right = aux;
aux->left = aux->right = NULL;
aux->bal = p2->bal = p->bal = zero;
}
void RotateLR(noh p, noh p1){
noh p2, aux;
aux = p;
p2 = p1->right;
p = p2;
p2->left = p1;
p2->right = aux;
aux->left = aux->right = NULL;
p1->left = p1->right = NULL;
aux->bal = p1->bal = p->bal = zero;
}
void RotateRR(noh p, noh p1){
noh p2, aux;
p2 = p1->right;
aux = p;
p = p1;
p->left = aux;
aux->left = aux->right = NULL;
aux->bal = p2->bal = p->bal = zero;
}
void RotateRL(noh p, noh p1){
noh p2, aux;
aux = p;
p2 = p1->left;
p = p2;
p2->right = p1;
p2->left = aux;
aux->left = aux->right = NULL;
p1->left = p1->right = NULL;
aux->bal = p1->bal = p->bal = zero;
}
答案 0 :(得分:1)
您的RotateLL / LR / RL / RR实现存在缺陷 - 它们在旋转中涉及的节点之间正确调整指针,但它们不会将指针更改为旧的根节点。这导致节点在旋转发生时丢失。
如果您在PrintTree()
的循环中插入对main()
的调用,您将会看到正在进行的操作。例如:
int number ('0' to exit): 1
check = 1
1 >> bal = 0
int number: 2
check = 1
1 >> bal = 1
2 >> bal = 0
int number: 3
check = 1
1 >> bal = 0
最简单的方法是让每个Rotate函数返回一个指向新根节点的指针,并在Insert()
中相应地更新指针。请记住,在某些情况下,Insert()
需要更新*p
以反映根节点已移动的事实!