AVL树是带AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的。
有平衡条件的二叉查找树,这个平衡条件要容易保持,保证树的深度是O(logN)。定义AVL树是每个节点左子树和右子数高度最多差1的平衡二叉树。AVL树是对BST树的一种优化,我们知道BST树插入的最坏情况是退化为线性数组,这样就大大降低了二分查找的效率,而AVL树在插入的时候会做旋转优化尽量让这个树左右平衡,从而提高了二分查找的效率。
和红黑树比较,它是严格的平衡二叉树,如果插入或删除后不满足平衡条件则会旋转调平衡,而旋转是耗费时间的,AVL树适用于插入删除比较少而查找多的情况。windows对进程地址空间的管理用到了AVL树。
核心:旋转
在每一次插入数值之后,树的平衡性都可能被破坏,这时可以通过一个简单的操作来矫正平衡——旋转。
旋转的目的就是减少高度,通过降低整棵树的高度来平衡。哪边的树高,就把那边的树向上旋转,通过旋转可以降低高度。
插入节点时分四种情况,四种情况对应的旋转方法是不同的:
例如对于被破坏平衡的节点 a 来说:
插入方式 | 描述 | 旋转方式 |
---|---|---|
LL | 在a的左子树根节点的左子树上插入节点而破坏平衡 | 右旋转 |
RR | 在a的右子树根节点的右子树上插入节点而破坏平衡 | 左旋转 |
LR | 在a的左子树根节点的右子树上插入节点而破坏平衡 | 先左旋后右旋 |
RL | 在a的右子树根节点的左子树上插入节点而破坏平衡 | 先右旋后左旋 |
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct node //avl树的声明
{
int key;
int height;
struct node *left;
struct node *right;
}node,*avl;
int get_height(avl root) //获取avl树的高度,这里空树高度定义为0
{
return ((root == NULL) ? 0 : (root->height));
}
avl left_left(avl root) //左左插入情况,需要右单旋
{
avl k = root->left;
root->left = k->right;
k->right = root;
root->height = max(get_height(root->left), get_height(root->right)) + 1; //更新旋转后节点的高度,每个节点的高度都是其左右子树最高高度加1
k->height = max(get_height(k->left), get_height(k->right)) + 1;
}
avl right_right(avl root) //右右插入情况,需要左单旋,原理同上
{
avl k = root->right;
root->right = k->left;
k->left = root;
root->height = max(get_height(root->left), get_height(root->right)) + 1;
k->height = max(get_height(k->left), get_height(k->right)) + 1;
}
avl left_right(avl root) //左右插入情况,需要先左旋再右旋
{
root->left = right_right(root->left); //对root->left左旋化为左左插入情况,然后再右旋
return left_left(root);
}
avl right_left(avl root) //右左插入情况,需要先右旋再左旋
{
root->right = left_left(root->right); //对root->right右旋化为右右插入情况,然后再左旋
return right_right(root);
}
avl insert(int key, avl &root) //对avl树的添加操作,传入添加的元素和根节点
{
if (root == NULL) //创建新节点
{
root = new node;
root->key = key;
root->left = root->right = NULL;
root->height = 0; //新创的节点是个空树,高度为0
}
else if (key < root->key)
{
root->left = insert(key, root->left); //递归向左插入
if (get_height(root->left) - get_height(root->right) == 2) //如果插入引起失衡,需要旋转调整
{
if (key < root->left->key) //左左插入情况
root = left_left(root);
else //否则就是左右插入情况
root = left_right(root);
}
}
else if (key > root->key)
{
root->right = insert(key, root->right);
if (get_height(root->right) - get_height(root->left) == 2)
{
if (key > root->right->key)
root = right_right(root);
else
root = right_left(root);
}
}
else
cout << "不允许添加相同元素的值!" << endl; //与bst一样,不允许重复插入相同元素
return root;
}