AVL树是带有平衡条件的二叉查找树,平衡条件是左子树的深度与右子树的深度差不超过1.
为了满足这个平衡条件,在插入节点时需要对树进行不断的调整,因为每次插入节点都会修正,所以左右子树的差最大只会等于2,修正后就只等于1了。一共有四种修正形式,分别是LL,LR,RL,RR,这里理解起来还是挺绕的,我用图来描述一下。
对于上面四个图来说,都是1节点不满足平衡条件了,这四种不满足条件的描述,分别对应RR,RL,LL,LR.这四种形式最后都可以修正为下面图中的这种形式,大家可以很清晰的看出来是怎么修正的。RR需要把1结点向左旋转;RL先把3结点向右旋转,再把1向左旋转;LL把3向右旋转;LR把1向左旋转,再把3向右旋转。所以我们可以总结:所谓的RR或者RL,代表的是失衡结点后两个子树的特征,第一个是左子树就是LX,第二个是左子树就是XL。旋转方向是跟结点失衡形式相反的,并且是从下往上旋转,比如RL,他就是先把第二个结点右转,再把第一个结点左转。这里还是有点绕的,大家仔细捋一捋,别搞混了。
我们的图是最简单的图,只有一个节点失衡,所以不用考虑去修正哪个节点。但是当树复杂的时候很有可能出现一个结点失衡所以导致它上面的结点也失衡的情况,比如下图。
由于插入了结点8使得7结点失衡了,同时也使得4结点失衡了,那么我该修正哪个结点呢?答案是修正最后失衡的那个结点。因为修正上面失衡的结点后他确实不失衡了,但是下面的结点还是失衡的。下图是修正好的树,会发现由于下面的结点不失衡了所以导致上面的结点也不失衡了。
在这里我还少说了一点就是,旋转的过程其实是把结点1的左子树2(或右),取代他的位置,然后自己作为2的右子树(或左)。但是如果2本来有右子树(或左子树)怎么办,那就把2的右子树作为1的左子树就好了。因为平衡二叉树的性质,2的右子树比1大比2小,所以这么做没有问题。听起来有点懵,我还是继续上面哪个图,我不修正7结点,修正4结点看看
5原来是6的左子树,修正后变成了4的右子树了,4原来的右子树是6,所以肯定没有右子树了,大家自己转个试试。(这种转是不能解决原先的失衡问题,就是给大家演示一下而已)
下面就是代码把,一定要把所有东西都想清楚再去写程序。
#include<stdio.h>//printf函数
#include<stdlib.h>//malloc函数
#include<windows.h>//max函数
/*AVL树,左深度与右深度差小于2*/
typedef struct TreeNode* Tree;
struct TreeNode
{
Tree left;
Tree right;
int elem;
int deep;
};
int Deep(Tree tree)
{
if(tree == NULL)
return -1;
else
return tree->deep;
}
Tree LL(Tree tree)//对左左的 右转
{
Tree p = tree->left;
tree->left = p->right;
p->right = tree;
tree->deep = max(Deep(tree->left),Deep(tree->right))+1;
p->deep = max(Deep(p->left),Deep(p->right))+1;
return p;
}
Tree RR(Tree tree)//对右右的 左转
{
Tree p = tree->right;
tree->right = p->left;
p->left = tree;
tree->deep = max(Deep(tree->left),Deep(tree->right))+1;
p->deep = max(Deep(p->left),Deep(p->right))+1;
return p;
}
Tree LR(Tree tree)
{
tree->left = RR(tree->left);
tree = LL(tree);
return tree;
}
Tree RL(Tree tree)
{
tree->right = LL(tree->right);
tree = RR(tree);
return tree;
}
Tree Insert(int elem,Tree tree)
{
if(tree == NULL)
{
tree = (Tree)malloc(sizeof(struct TreeNode));
if(tree==NULL)
printf("Error");
else
{
tree->left = NULL;
tree->right = NULL;
tree->elem = elem;
}
}
else
{
if(elem > tree->elem)
{
tree->right =Insert(elem,tree->right);//在右边加了只可能右边比左边大
if(Deep(tree->right) - Deep(tree->left)==2)
{
if(elem > tree->right->elem)
tree = RR(tree);
else
tree = RL(tree);
}
}
else if(elem < tree->elem)
{
tree->left = Insert(elem,tree->left);
if(Deep(tree->left) - Deep(tree->right)==2)
{
if(elem < tree->left->elem)
tree = LL(tree);
else
tree = LR(tree);
}
}
}
tree->deep = max(Deep(tree->left),Deep(tree->right))+1;
return tree;
}
void InOrderTraverse(Tree tree)
{
if(tree == NULL) return;
InOrderTraverse(tree->left);
printf("%d",tree->elem);
InOrderTraverse(tree->right);
}
void main()
{
Tree root = NULL;
root = Insert(5,root);
//root = Insert(3,root);
//root = Insert(7,root);
//root = Insert(4,root);
//root = Insert(3,root);
InOrderTraverse(root);
}