- 性质:①左子树 < 根结点; ②右子树 > 根结点; ③| H(left) - H(right) | <= 1
- 优点: 由于对于每个结点的左右子树的树高做了限制,所以整棵树不会退化成一个链表
- 左旋和右旋(用于调整树高)
①左旋:原根结点变为新根结点的左子树,新根结点的左子树变为原根结点的右子树。如下图:
②右旋:原根结点变为新根结点的右子树,新根结点的右子树变为原根结点的左子树。如下图: - 失衡类型
(1)失衡是一个动态的过程(边插入/删除边调整)
(2)讨论失衡类型时,任何一棵树都是一棵大树中的一小部分
(3)在讨论失衡类型时,每一种平衡情况:当前根节点不平衡,其左右子树的结点都平衡
(4)四种失衡类型如下图:
①LL型—>大右旋
②LR型—>先抓k2进行小左旋,然后再抓k1进行大右旋
③RL型—>抓k3小右旋,抓k1进行大左旋
④RR型—>大左旋
5. AVL树的特点
AVL树是一种高度平衡的树,查找效率非常高。但是因为每次插入、删除都要做调整,所以对于有频繁插入、删除操作的数据结构,就要思考要不要更换数据结构。
6. AVL树插入过程图示:
- AVL树插入与删除的代码演示
#include<stdio.h>
#include <stdlib.h>
typedef struct Node{
int key, h;
struct Node *lchild, *rchild;
} Node;
__attribute__((constructor)) //让这个方法先于主函数执行
void init_NIL(){
NIL->key = NIL->h = 0;
NIL->lchild = NIL->rchild;
return ;
}
Node *getNewNode(int key){
Node *p = (Node *)malloc(sizeof(Node));
p->key = key;
p->h = 1;
p->lchild = p->rchild = NIL; //NIL:虚拟空地址(空结点),访问NULL地址的高度可能会导致程序崩溃
return p;
}
#define max(a, b) ((a) > (b) ? (a) : (b))
void update_height(Node *root){
root->h = max(root->lchild->h, root->rchild->h) + 1;
return ;
}
//左旋
Node *left_rotate(Node *root){
Node *new_root = root->rchild; //新根结点为原根结点的右子树
root->rchild = new_root->lchild; //原根结点的右子树变为新根结点的左子树
new_root->lchild = root; //新根结点的左子树变为原根结点
update_height(root);
update_height(new_root);
return new_root;
}
Node *right_rotate(Node *root){
Node *new_root = root->lchild;
root->lchild =new_root->rchild;
new_root->rchild = root;
update_height(root);
update_height(new_root);
return new_root;
}
//返回经过平衡调整后新根结点的值
Node *maintain(Node *root){
if(abs(root->lchild->h - root->rchild->h) < 2) return root; //平衡
if(root->lchild->h > root->rchild->h){//L
if(root->lchild->lchild->h < root->lchild->rchild->h){ //R
root->lchild = left_rotate(root->lchild);
}
// L
root = right_rotate(root);
} else { //R
if(root->rchild->rchild->h < root->rchild->lchild->h){ //L
root->rchild = right_rotate(root->rchild);
}
//R
root = left_rotate(root);
}
return root;
}
Node *insert(Node *root, int key){
if(root == NIL) return getNewNode(key);
if(root->key == key) return root;
if(root->key > key) root->lchild = insert(root->lchild, key); //向左子树插入
else root->rchild = insert(root->rchild, key); //向右子树插入
update_height(root);
return maintain(root); //返回一个经过平衡调整以后的新根结点的地址
}
Node *erase(Node *root, int key){
if(root == NIL) return root;
if(root->key > key) root->lchild = erase(root->lchild, key); //到左子树删除
else if(root->key < key) root->rchild = erase(root->rchild, key); //到右子树删除
else {
if(root->lchild == NIL || root->rchild == NIL){
Node *temp = root->lchild != NIL ? root->lchild : root->rchild;
free(root);
return temp;
} else { //n = 2
Node *temp = root->lchild; //前驱
while(temp->rchild != NIL) temp = temp->rchild; //左子树中最大值(最右边的结点)
root->key = temp->key;
root->lchild = erase(root->lchild, temp->key);
}
}
update_height(root);
return maintain(root);
}
void clear(Node *root){
if(root == NIL) return ;
clear(root->lchild);
clear(root->rchild);
free(root);
return ;
}
//先序遍历
void output(Node *root){
if(root == NIL) return ;
printf_node(root);
output(root->lchild);
output(root->rchild);
return ;
}
int main(){
//测试代码
return 0;
}
要是对您有帮助,点个赞再走吧~ 欢迎评论区讨论~