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

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

### 序列 `12365` 插入AVL 中的旋转过程 #### 初始状态 当向 AVL 依次插入序列 `1`, `2`, `3`, `6`, 和 `5` 时,每一步都需要检查是否仍然保持平衡。如果不平衡,则需要执行相应的旋转操作。 --- #### 插入第一个节点 `1` 初始状态下,AVL 插入节点 `1` 后,的状态如下: ``` 1 ``` 此时无需任何旋转操作,因为只有一个节点[^1]。 --- #### 插入第二个节点 `2` 接着插入节点 `2`,变成线性结构: ``` 1 \ 2 ``` 由于根节点 `1` 的左右子高度差为 1(满足 AVL 平衡条件),因此不需要进行旋转[^1]。 --- #### 插入第三个节点 `3` 再插入节点 `3`,变为: ``` 1 \ 2 \ 3 ``` 现在根节点 `1` 的左右子高度差为 2,违反了 AVL 平衡条件。这种情况属于 **LL 类型失衡**,需要对根节点 `1` 进行 **右单旋** 操作[^2]。 右单旋后,的结构更新为: ``` 2 / \ 1 3 ``` 此时恢复平衡。 --- #### 插入第四个节点 `6` 接下来插入节点 `6`,变为: ``` 2 / \ 1 3 \ 6 ``` 当前仍然是平衡的,因为所有节点的左右子高度差均不超过 1[^1]。 --- #### 插入第五个节点 `5` 最后插入节点 `5`,变为: ``` 2 / \ 1 3 \ 6 / 5 ``` 此时,节点 `3` 的左右子高度差为 2,出现了 **RL 类型失衡**。为了恢复平衡,需要先对节点 `6` 执行 **左单旋**,然后再对节点 `3` 执行 **右单旋**[^4]。 第一步:对节点 `6` 执行左单旋: ``` 2 / \ 1 3 \ 5 \ 6 ``` 第二步:对节点 `3` 执行右单旋: ``` 2 / \ 1 5 / \ 3 6 ``` 最终,整个恢复平衡。 --- ### 总结 经过以上步骤,序列 `12365` 被成功插入AVL 中,并完成了必要的旋转操作。最终的 AVL 结构为: ``` 2 / \ 1 5 / \ 3 6 ``` --- ### Python 实现代码示例 以下是基于上述逻辑的 AVL 插入算法实现: ```python class TreeNode: def __init__(self, key): self.key = key self.left = None self.right = None self.height = 1 class AVLTree: def insert(self, root, key): if not root: return TreeNode(key) if key < root.key: root.left = self.insert(root.left, key) else: root.right = self.insert(root.right, key) root.height = 1 + max(self.get_height(root.left), self.get_height(root.right)) balance_factor = self.get_balance(root) # LL Case if balance_factor > 1 and key < root.left.key: return self.right_rotate(root) # RR Case if balance_factor < -1 and key > root.right.key: return self.left_rotate(root) # LR Case if balance_factor > 1 and key > root.left.key: root.left = self.left_rotate(root.left) return self.right_rotate(root) # RL Case if balance_factor < -1 and key < root.right.key: root.right = self.right_rotate(root.right) return self.left_rotate(root) return root def get_height(self, node): if not node: return 0 return node.height def get_balance(self, node): if not node: return 0 return self.get_height(node.left) - self.get_height(node.right) def right_rotate(self, z): y = z.left T3 = y.right y.right = z z.left = T3 z.height = 1 + max(self.get_height(z.left), self.get_height(z.right)) y.height = 1 + max(self.get_height(y.left), self.get_height(y.right)) return y def left_rotate(self, z): y = z.right T2 = y.left y.left = z z.right = T2 z.height = 1 + max(self.get_height(z.left), self.get_height(z.right)) y.height = 1 + max(self.get_height(y.left), self.get_height(y.right)) return y def pre_order_traversal(node): if not node: return [] result = [node.key] result += pre_order_traversal(node.left) result += pre_order_traversal(node.right) return result # 测试代码 tree = AVLTree() root = None keys = [1, 2, 3, 6, 5] for key in keys: root = tree.insert(root, key) print(pre_order_traversal(root)) # 输出最终的前序遍历结果 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值