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;
root=k;
return root;
}
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;
root=k;
return root;
}
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 = 1; //新创的节点高度为1
}
else if (key < root->key)
{
root->left = insert(key, root->left); //递归向左插入
updatahegiht(root);
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);
updatahegiht(root);
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;
}
PAT1066 Root of AVL Tree (25 分)
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print the root of the resulting AVL tree in one line.
Sample Input 1:
5
88 70 61 96 120
Sample Output 1:
70
Sample Input 2:
7
88 70 61 96 120 90 65
Sample Output 2:
88
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct node
{
int key;
int height;
struct node *left;
struct node *right;
}node,*avl;
int get_height(avl root) //获取树高,计算是否失衡,失衡则做出相应的旋转操作
{
return ((root == NULL) ? 0 : (root->height));
}
void updatahegiht(avl &root) //更新树高
{
root->height = max(get_height(root->left), get_height(root->right)) + 1;
}
avl left_left(avl root)
{
avl k = root->left;
root->left = k->right;
k->right = root;
updatahegiht(root);
updatahegiht(k);
root=k;
return root;
}
avl right_right(avl root)
{
avl k = root->right;
root->right = k->left;
k->left = root;
updatahegiht(root);
updatahegiht(k);
root=k;
return root;
}
avl left_right(avl root)
{
root->left = right_right(root->left);
return left_left(root);
}
avl right_left(avl root)
{
root->right = left_left(root->right);
return right_right(root);
}
avl insert(int key, avl root)
{
if (root == NULL)
{
root = new node;
root->key = key;
root->left = root->right = NULL;
root->height = 1;
}
else if (key < root->key)
{
root->left = insert(key, root->left);
updatahegiht(root);
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);
updatahegiht(root);
if (get_height(root->right) - get_height(root->left) == 2)
{
if (key > root->right->key)
root = right_right(root);
else
root = right_left(root);
}
}
return root;
}
int main(){
int n;
scanf("%d",&n);
avl root=NULL; //注意要赋初值!
for(int i=0;i<n;i++){
int tmp;
scanf("%d",&tmp);
root=insert(tmp,root);
}
printf("%d",root->key);
return 0;
}