I was implementing an AVL tree and its operations like rotation.
And in the end when I tried to insert an array, the result seemed
different. And anyone tell me what went wrong! Thank you !
#include <stdio.h>
#include <stdlib.h>
#define LH +1
#define RH -1
#define EQ 0
typedef int BOOL;
typedef struct node
{
int bf;
struct node *left;
struct node *right;
int val;
}treeNode;
void L_Rotate(treeNode **T)
{
treeNode *p = (*T)->right;
(*T)->right = p->left;
p->left=*T;
*T=p;
}
void R_Rotate(treeNode **T)
{
treeNode *p=(*T)->left;
(*T)->left=p->right;
p->right=*T;
*T=p;
}
void Left_Balance(treeNode **T)
{
treeNode *p=(*T)->left;
treeNode *q;
switch(p->bf)
{
case LH:
p->bf=(*T)->bf=EQ;
R_Rotate(T);
break;
case RH:
q = p->right;
switch(q->bf)
{
case LH:
(*T)->bf=RH;
p->bf=EQ;
break;
case EQ:
(*T)->bf=q->bf=EQ;
break;
case RH:
p->bf=LH;
(*T)=EQ;
break;
}
q->bf=EQ;
L_Rotate(&p);
R_Rotate(T);
}
}
void Right_Balance(treeNode **T)
{
treeNode *p=(*T)->right;
treeNode *q;
switch(p->bf)
{
case RH:
(*T)->bf=p->bf=EQ;
L_Rotate(T);
break;
case LH:
q=p->left;
switch(q->bf)
{
case LH:
(*T)->bf=EQ;
p->bf=RH;
break;
case RH:
(*T)->bf=LH;
p->bf=EQ;
break;
}
q->bf=EQ;
R_Rotate(&p);
L_Rotate(T);
}
}
int insertAVL (treeNode **T,int key, BOOL *taller)
{
if(!*T)
{
*T=malloc(sizeof(treeNode));
if(!*T) return 0;
(*T)->left=(*T)->right=NULL;
(*T)->bf=EQ;
*taller = 1;
(*T)->val=key;
}
else
{
if(key==(*T)->val)
{
*taller= 0;
return 0;
}
else if(key<(*T)->val)
{
if(!insertAVL(&(*T)->left,key,taller)) return 0;
if(*taller)
{
switch((*T)->bf)
{
case LH:
Left_Balance(T);
*taller=0;
break;
case RH:
(*T)->bf=EQ;
*taller =0;
break;
case EQ:
(*T)->bf=LH;
*taller =1;
break;
}
}
}
else
{
if(!insertAVL(&(*T)->right,key,taller)) return 0;
if(*taller)
{
switch((*T)->bf)
{
case LH:
(*T)->bf=EQ;
*taller=0;
break;
case EQ:
(*T)->bf=RH;
*taller=1;
break;
case RH:
Right_Balance(T);
*taller =0;
break;
}
}
}
}
return 1;
}
void preOrder(treeNode *T)
{
if(!T)
{
return;
}
printf("%d\n",T->val);
preOrder(T->left);
preOrder(T->right);
}
int main() {
int i;
int a[10]={3,2,1,4,5,6,7,10,9,8};
treeNode *T=NULL;
BOOL taller;
for(i=0;i<10;i++)
{
insertAVL(&T,a[i],&taller);
preOrder(T);
printf("-------\n");
}
return 0;
}
I traversed the tree after each insertion into the tree, the results are
right until I inserted 9 into the tree.
When you modify the tree (or a subtree), you pass in a pointer to the head pointer, so that changes are reflected in the original link, either the global head or one of the left/right links of a node. That's a good practice, in my opinion.
When you balance the tree, you do the same, but there's a pitfall:
treeNode *p = (*T)->left;
// ... some stuff ...
L_Rotate(&p);
R_Rotate(T);
Here, p
is a local copy of (*T)->left
. You end up modifying a local variable (which will go out of scope right away), but not the actual link in the parent node; the node is "eaten".
You could either make p
a treeNode **
as well or, given that you don't change the pointer itself, change your rotation code to:
L_Rotate(&(*T)->left);
R_Rotate(T);
Likewise for the other rotation.
I also noticed your balance left/right functions aren't symmetrical and the right-balancing code misses the EQ case. I did some tries to add it and to rewrite Right_Balance
to be symmetrical of Left_Balance
but that solves nothing. The problem is not (only) here.
If I am not wrong to manage an AVL you have to take into account the height of each cell to decide how to balance after the insertion of a new value.
In your case there is no height but bf able to get the 3 values LH/RH/EQ, in a way bf is equivalent to a height into the range 1 up to 3. But after the insertion of 10 the cell having the value 4 has in fact the height 4 and you cannot manage that and for me this is why you cannot after insert 9 correctly after 10.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.