对于有N个节点的二叉排序树,我们期望其高度是LogN,但实际情况往往事与愿违。在极端情况下,比如在生成二叉排序树时,其插入的序列是个有序数列,此时的二叉树结构类似于一个链表,各个操作的时间与链表的操作无异。因此,通过某种方法使得二叉树左右子树深度一样或者相差不大是有意义和必要的。这就是平衡二叉树,也叫AVL树。
1.AVL树定义
平衡二叉树要么是空树,要么满足以下性质
- 左右子树的高度之差的绝对值不超过1;
- 左右子树也分别为AVL树。
例如下图中,左边是AVL树,但是右边的不是,因为左子树的高度为2,右边为0,相差为2,在节点19处产生了不平衡。
2.AVL树的平衡过程
二叉排序树在插入节点或者删除节点时,可能导致树的不平衡,此时需要通过某些操作来平衡二叉树。一般来说,有4中不平衡的情况,如下图:
①LL:左左,插入或者删除一个节点导致根节点的左子树高度比根的右子树的高度大2.
②RR:右右,插入或者删除一个节点导致根节点的右子树高度比根的左子树的高度大2.
③LR:左右,插入或者删除一个节点导致根节点的左子树高度比根的右子树的高度大2.
④RL:右左,插入或者删除一个节点导致根节点的右子树高度比根的左子树的高度大2.
2.1 LL或者RR
这两种情况是对称的,所以处理办法也是相对称的,通过一次旋转即可,如下图:
2.2 RL或者LR
这两种情况稍微复杂,但也是对称的,通过两次旋转即可,如下图:
3.代码
class AVLTree
{
public:
AVLTree(){}
int data;
int height;
AVLTree *left, *right;
};
static int getHeight(AVLTree* node)
{
return node->height;
}
static int getMax(int a, int b)
{
return (a>b)?a:b;
}
AVLTree* left_left_rotate(AVLTree* k1)
{
AVLTree *k2 = k1->left;
k2->right = k1;
k1->left = k2->right;
k1->height = getMax(getHeight(k1->left),getHeight(k1->right))+1;
k2->height = getMax(getHeight(k2->left),getHeight(k1))+1;
return k2;
}
AVLTree* right_right_rotate(AVLTree* k1)
{
AVLTree *k2 = k1->right;
k2->left = k1;
k1->right = k2->left;
k1->height = getMax(getHeight(k1->right),getHeight(k1->left))+1;
k2->height = getMax(getHeight(k2->right),getHeight(k1))+1;
return k2;
}
AVLTree* left_right_rotate(AVLTree *k3)
{
k3->left = right_right_rotate(k3->left);
return left_left_rotate(k3);
}
AVLTree* right_left_rotate(AVLTree *k3)
{
k3->right = left_left_rotate(k3->left);
return right_right_rotate(k3);
}
4.插入节点
void insertNode(AVLTree* x,int key)
{
if(x == NULL)
{
x = (AVLTree*)malloc(sizeof(AVLTree));
if(x == NULL)
printf("malloc failure!");
else
{
x->data = key;
x->height = 1;
x->left = x->right = NULL;
}
}
else
{
if(key > x->data)
{
///右子树
insertNode(x->right,key);
if(getHeight(x->right)-getHeight(x->left)>1)
{
//RR
if(key>x->right->data)
x = right_right_rotate(x);
else//RL
x = right_left_rotate(x);
}
}
else if(key < x->data)
{
///左子树
insertNode(x->left,key);
if(getHeight(x->left)-getHeight(x->right)>1)
{
//LR
if(key > x->left->data)
x = left_right_rotate(x);
else//LL
x = left_left_rotate(x);
}
}
else//插入值在树中已存在
printf("值%d已存在",key);
}
x->height = getMax(getHeight(x->left),getHeight(x->right))+1;
}