普通的二叉查找树很容易导致某一侧的子树高度远远超过另一侧,这就导致了搜索效率的降低。AVL树(自平衡二叉查找树的诞生就是为了解决此类问题),和之前的BST树很类似,但是要添加上平衡因子,并在插入或删除某结点后进行平衡。
上次代码的问题所在就是Delete功能在删除结点进行平衡时出现的错误,Delete操作的时候,要小心的判断是哪种旋转,然后再去解决,同时还要注意,删除结点后应该先判断这个树是否为空,然后再决定是否需要平衡。(现在心力交瘁)
关于平衡说一下个人判断小技巧:
如果一个树(T),进行插入操作插入点在左子树(T->Left)上,那么有两种情况,树仍然平衡,或不再平衡,如果仍然平衡那就不需要进一步操作了,如果不再平衡,那么问题一定是左子树造成的,我们这个时候需要判断左子树(T->Left)的左子树(T->Left->Left)和右子树(T->Left->Right)的高度差,如果差为-1,则代表这个左子树(T->Left)仅有一个右子树,这个时候就需要LR旋转了(本程序的DoubleRotateWithLeft()函数),如果差是1或者0,那么只需要LL旋转即可(本程序的SingleRotateWithLeft()函数)
如果是插入点在右子树上,操作刚好和上述过程相反。
同理删除右子树的结点近似于增添左子树的结点,删除左子树的结点近似于增添右子树的结点
这个还是亲自动手画画图,然后多敲代码多测试吧。
这个树学着挺绕的,但是本质问题只要能理解了,那么LL,RR,LR,RL四种旋转,包括插入删除时候的平衡就很容易了。
测试数据:(Insert一次,Delete两次,每次都以0为结束标志,0不参与树的插入和删除)
15 6 50 4 7 23 71 5 0
23 0
71 0
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct AvlNode
{
ElemType Element;
AvlNode *Left;
AvlNode *Right;
int Height;
} AvlNode,*AvlTree,*Position;
AvlTree MakeEmpty(AvlTree T);
Position Find(ElemType X,AvlTree T);
Position FindMin(AvlTree T);
Position FindMax(AvlTree T);
AvlTree Insert(ElemType X,AvlTree T);
AvlTree Delete(ElemType X,AvlTree T);
ElemType Retrieve(Position P);
static int Height(Position P)
{
if(P==NULL)
return -1;
else
return P->Height;
}
AvlTree MakeEmpty(AvlTree T)
{
if(T!=NULL)
{
MakeEmpty(T->Left);
MakeEmpty(T->Right);
free(T);
}
return NULL;
}
Position Find(ElemType X,AvlTree T)
{
if(T==NULL)
{
printf("Element not found\n");
return NULL;
}
if(X<T->Element)
return Find(X,T->Left);
else if(X>T->Element)
return Find(X,T->Right);
else
return T;
}
Position FindMin(AvlTree T)
{
if(T==NULL)
{
printf("Element not found\n");
return NULL;
}
if(T->Left)
return FindMin(T->Left);
else
return T;
}
Position FindMax(AvlTree T)
{
if(T==NULL)
{
printf("Element not found\n");
return NULL;
}
if(T->Right)
return FindMax(T->Right);
else
return T;
}
static int Max(int Lhs,int Rhs)
{
return Lhs > Rhs ? Lhs : Rhs;
}
static Position SingleRotateWithLeft(Position K2)
{
Position K1;
K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2;
K2->Height = Max(Height(K2->Left),Height(K2->Right))+1;
//Height(K1->Right) == K2->Height
K1->Height = Max(Height(K1->Left),K2->Height)+1;
return K1;
}
static Position SingleRotateWithRight(Position K1)
{
Position K2;
K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1;
K1->Height = Max(Height(K1->Left),Height(K1->Right))+1;
K2->Height = Max(K1->Height,Height(K2->Right))+1;
}
static Position DoubleRotateWithLeft(Position K3)
{
K3->Left = SingleRotateWithRight(K3->Left);
return SingleRotateWithLeft(K3);
}
static Position DoubleRotateWithRight(Position K1)
{
K1->Right = SingleRotateWithLeft(K1->Right);
return SingleRotateWithRight(K1);
}
AvlTree Insert(ElemType X,AvlTree T)
{
if(T==NULL)
{
T = (AvlTree)malloc(sizeof(AvlNode));
if(T==NULL)
{
printf("Malloc Error\n");
exit(1);
}
T->Element = X;
T->Height = 0;
T->Left = T->Right = NULL;
}
else if(X<T->Element)
{
T->Left = Insert(X,T->Left);
if(Height(T->Left) - Height(T->Right)==2)
{
if(X<T->Left->Element)
T = SingleRotateWithLeft(T);
else
T = DoubleRotateWithLeft(T);
}
}
else if(X>T->Element)
{
T->Right = Insert(X,T->Right);
if(Height(T->Right) - Height(T->Left)==2)
{
if(X>T->Right->Element)
T = SingleRotateWithRight(T);
else
T = DoubleRotateWithRight(T);
}
}
T->Height = Max(Height(T->Left),Height(T->Right))+1;
return T;
}
AvlTree Delete(ElemType X,AvlTree T)
{
Position temp;
if(T==NULL)
{
printf("Element not found\n");
return NULL;
}
else if(X<T->Element)
{
T->Left = Delete(X,T->Left);
}
else if(X>T->Element)
{
T->Right = Delete(X,T->Right);
}
else if(T->Left && T->Right)
{
temp = FindMin(T->Right);
T->Element = temp->Element;
T->Right = Delete(T->Element,T->Right);
}
else
{
temp = T;
if(T->Left==NULL)
T = T->Right;
else if(T->Right==NULL)
T = T->Left;
free(temp);
}
if(T!=NULL)
{
int balance = Height(T->Left)-Height(T->Right);
if(balance==2)
{
int balance2 = Height(T->Left->Left)-Height(T->Left->Right);
if(balance2==-1)
{
T = DoubleRotateWithLeft(T);
}
else
{
T = SingleRotateWithLeft(T);
}
}
else if(balance==-2)
{
int balance2 = Height(T->Right->Left)-Height(T->Right->Right);
if(balance2==-1)
{
T = DoubleRotateWithRight(T);
}
else
{
T = SingleRotateWithRight(T);
}
}
T->Height = Max(Height(T->Left),Height(T->Right))+1;
}
return T;
}
ElemType Retrieve(Position P)
{
return P->Element;
}
int Depth(AvlTree T)
{
int Ldepth,Rdepth;
if(T==NULL)
return 0;
if(T->Left)
Ldepth = Depth(T->Left);
else
Ldepth = 0;
if(T->Right)
Rdepth = Depth(T->Right);
else
Rdepth = 0;
return Ldepth>Rdepth ? Ldepth+1:Rdepth+1;
}
void PreOrderTraversal(AvlTree T)
{
if(T==NULL)
return ;
printf("%d ",T->Element);
PreOrderTraversal(T->Left);
PreOrderTraversal(T->Right);
}
void InOrderTraversal(AvlTree T)
{
if(T==NULL)
return ;
InOrderTraversal(T->Left);
printf("%d ",T->Element);
InOrderTraversal(T->Right);
}
void PostOrderTraversal(AvlTree T)
{
if(T==NULL)
return ;
PostOrderTraversal(T->Left);
PostOrderTraversal(T->Right);
printf("%d ",T->Element);
}
int main()
{
AvlTree T=NULL;
T = MakeEmpty(T);
int depth = Depth(T);
printf("The depth of this tree is :%d\n",depth);
while(1)
{
int Element;
scanf("%d",&Element);
if(Element==0)
break;
else
T = Insert(Element,T);
}
depth = Depth(T);
printf("The depth of this tree is :%d\n",depth);
printf("PreOrderTraversal: ");
PreOrderTraversal(T);
printf("\n");
printf("InOrderTraversal: ");
InOrderTraversal(T);
printf("\n");
printf("PostOrderTraversal: ");
PostOrderTraversal(T);
printf("\n");
while(1)
{
int Element;
scanf("%d",&Element);
if(Element==0)
break;
else
T = Delete(Element,T);
}
printf("---After Delete---\n");
depth = Depth(T);
printf("The depth of this tree is :%d\n",depth);
printf("PreOrderTraversal: ");
PreOrderTraversal(T);
printf("\n");
printf("InOrderTraversal: ");
InOrderTraversal(T);
printf("\n");
printf("PostOrderTraversal: ");
PostOrderTraversal(T);
printf("\n");
while(1)
{
int Element;
scanf("%d",&Element);
if(Element==0)
break;
else
T = Delete(Element,T);
}
printf("---After Delete---\n");
depth = Depth(T);
printf("The depth of this tree is :%d\n",depth);
printf("PreOrderTraversal: ");
PreOrderTraversal(T);
printf("\n");
printf("InOrderTraversal: ");
InOrderTraversal(T);
printf("\n");
printf("PostOrderTraversal: ");
PostOrderTraversal(T);
printf("\n");
return 0;
}
The depth of this tree is :0
15 6 50 4 7 23 71 5 0
The depth of this tree is :4
PreOrderTraversal: 15 6 4 5 7 50 23 71
InOrderTraversal: 4 5 6 7 15 23 50 71
PostOrderTraversal: 5 4 7 6 23 71 50 15
23 0
---After Delete---
The depth of this tree is :4
PreOrderTraversal: 15 6 4 5 7 50 71
InOrderTraversal: 4 5 6 7 15 50 71
PostOrderTraversal: 5 4 7 6 71 50 15
71 0
---After Delete---
The depth of this tree is :3
PreOrderTraversal: 6 4 5 15 7 50
InOrderTraversal: 4 5 6 7 15 50
PostOrderTraversal: 5 4 7 50 15 6
Process returned 0 (0x0) execution time : 10.002 s
Press any key to continue.