AVL平衡树是一种二叉搜索树,且每个节点保持平衡。
节点平衡的标准是节点的左右子树高度的差属于[-1, 0, 1]之一。
另外,树的高度等于从根结点到最深叶子节点的步数。特别地,root=NULL,高度=-1;叶子节点的高度等于0。
如果树种某节点不满足节点的平衡标准,那么需要对不满足标准的节点进行旋转。
总共分四类:left-left,left-right,right-right,right-left,如下图。具体的旋转方法也如下图所示。其中,ABCD可以为NULL,也可以不为NULL。在旋转中,需要对ABCD和345重新分配位置,且一个点都不能少。
注意,left-left与left-right的区别在root->left的平衡标准是否为-1,而right-right与right-left的区别在于root->right的平衡标准是否为1。
往AVL插入一个新值的过程:
1. 插入新值
2. 判断是否有节点失去平衡,如果是,修正该点平衡(如图1,搬动调整ABCD)
3.更新每个节点的高度,可以用来判断节点的平衡度。
下面是在Hackerrank上数据结构题目:向一棵AVL树插入新值,且所有点的值均不相同。
题目链接:https://www.hackerrank.com/challenges/self-balancing-tree(已通过)
<span style="font-size:14px;">/*
node 树的节点
ht 节点高度
val 节点值
left 左子树根
right右子树根
*/
/*
typedef struct node
{
int val;
struct node* left;
struct node* right;
int ht;
} node;
*/
node * insert(node * root,int val)
{
//1. 向以root为根的AVL插入val
//新值一定插入为叶子节点
if(root == NULL){
node *p = new node;
p->val = val;
p->ht = 0;
p->left = NULL;
p->right = NULL;
return p;
}
if(root->val > val){
root->left = insert(root->left, val);
}
else if(root->val < val){
root->right = insert(root->right, val);
}
else{
return root;
}
//2. 判断节点root是否平衡并进行旋转
int lh(-1), rh(-1);
if(root->left != NULL){
lh = root->left->ht;
}
if(root->right != NULL){
rh = root->right->ht;
}
node *rootL, *rootR, *tmp;
if(lh - rh >= 2){ //left
int h1(-1), h2(-1);
if(root->left->left != NULL)
h1 = root->left->left->ht;
if(root->left->right != NULL)
h2 = root->left->right->ht;
if(h1 - h2 == -1){ //left-right
rootL = root->left;
root->left = rootL->right;
tmp = root->left->left;
root->left->left = rootL;
rootL->right = tmp;
}
rootL = root->left; //left-left
tmp = rootL->right;
rootL->right = root;
root->left = tmp;
root = rootL;
}
else if(lh - rh <= -2){ //right
int h1(-1), h2(-1);
if(root->right->left != NULL)
h1 = root->right->left->ht;
if(root->right->right != NULL)
h2 = root->right->right->ht;
if(h1 - h2 == 1){ //right-left
rootR = root->right;
root->right = rootR->left;
tmp = root->right->right;
root->right->right = rootR;
rootR->left = tmp;
}
rootR = root->right; //right-right
tmp = rootR->left;
rootR->left = root;
root->right = tmp;
root = rootR;
}
//3. 更新root和其左右子树的高度
rootR = root->right;
if(rootR != NULL)
rootR->ht = 1 + max( (rootR->left == NULL? -1: rootR->left->ht), (rootR->right == NULL? -1: rootR->right->ht) );
rootL = root->left;
if(rootL != NULL)
rootL->ht = 1 + max( (rootL->left == NULL? -1: rootL->left->ht), (rootL->right == NULL? -1: rootL->right->ht) );
root->ht = 1 + max( (root->left == NULL? -1: root->left->ht), (root->right == NULL? -1: root->right->ht) );
return root;
}</span>