AVL树(含图解)

  1. 性质:①左子树 < 根结点; ②右子树 > 根结点; ③| H(left) - H(right) | <= 1
  2. 优点: 由于对于每个结点的左右子树的树高做了限制,所以整棵树不会退化成一个链表
  3. 左旋和右旋(用于调整树高)
    ①左旋:原根结点变为新根结点的左子树,新根结点的左子树变为原根结点的右子树。如下图:
    ②右旋:原根结点变为新根结点的右子树,新根结点的右子树变为原根结点的左子树。如下图:请添加图片描述
  4. 失衡类型
    (1)失衡是一个动态的过程(边插入/删除边调整)
    (2)讨论失衡类型时,任何一棵树都是一棵大树中的一小部分
    (3)在讨论失衡类型时,每一种平衡情况:当前根节点不平衡,其左右子树的结点都平衡
    (4)四种失衡类型如下图:

①LL型—>大右旋

②LR型—>先抓k2进行小左旋,然后再抓k1进行大右旋

③RL型—>抓k3小右旋,抓k1进行大左旋

④RR型—>大左旋请添加图片描述
5. AVL树的特点
AVL树是一种高度平衡的树,查找效率非常高。但是因为每次插入、删除都要做调整,所以对于有频繁插入、删除操作的数据结构,就要思考要不要更换数据结构。
6. AVL树插入过程图示请添加图片描述

  1. 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;
}

要是对您有帮助,点个赞再走吧~ 欢迎评论区讨论~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值