🎨
Notes
  • 持续更新中...
  • articles
    • browser
      • 深入理解现代浏览器 - 导航
      • 深入理解现代浏览器 - 架构
      • 深入理解现代浏览器 - 交互
      • 深入理解现代浏览器 - 渲染器进程
    • dsa
      • DSA - 并查集
      • DSA - 哈希表
      • DSA - AVL 树
      • DSA - 二叉树
      • 快速选择
      • Big O 算法复杂度
      • DSA - 栈和队列
      • DSA - 前缀树 Trie
      • DSA - 图
      • DSA - 链表
      • DSA - 递归
    • typescript
      • TypeScript 学习笔记 - 任意属性 (Indexable Types)
      • 力扣的 TypeScript 面试题
      • TypeScript 学习笔记 - as const
      • TypeScript 学习笔记 - infer
    • network
      • Internet Protocol (IP)
      • 计算机网络基础
      • 如何分辨同源和同站
      • DNS 如何查询 IP 地址?
    • vue
      • Nuxt.js 入门
      • 从零实现一个 Mini Vue
      • 从零实现一个简单的 VDOM 引擎
      • 从零实现一个响应式状态管理
    • sorting
      • 排序 - 归并排序
      • 排序 - 冒泡排序
      • 排序 - 选择排序
      • 排序 - 计数排序
      • 排序 - 插入排序
    • compile
      • Compiler and Interpreter
      • Just-In-Time (JIT) Compilers
      • 编译流程
    • others
      • 什么是上下文无关语法
      • 如何在终端打印出有颜色的字
    • dev-ops
      • github-actions
        • GitHub Action 简介
        • GitHub Actions for CI
    • workflow
      • 用 Node 写一个 cli
      • 如何规范 git commit 信息
      • 如何监听 git hooks
      • 如何规范代码风格 - prettier
      • 如何发布一个 npm package
      • 如何规范代码质量 - eslint
    • design-pattern
      • 代理模式
      • 单例模式
      • 策略模式
    • security
      • 点击劫持
      • CSP 内容安全策略
    • javascript
      • 尾调用优化
      • 4种常见的内存泄漏及解决方法
    • unit-test
      • Test Vuejs Application - Chapter 2
      • Test Vuejs Application - Chapter 1
      • Vue Unit Test Intro
    • performance
      • HTTP 缓存
      • 如何优化图片资源
Powered by GitBook
On this page
  • 概念
  • 操作
  • 插入
  • 旋转
  • 删除
  • 代码
  • 复杂度
  • 可视化
  • AVL 树 vs 红黑树

Was this helpful?

  1. articles
  2. dsa

DSA - AVL 树

概念

AVL 树是一棵平衡的二叉搜索树(BST),也就是升级版就的 BST。它的定义范围比 BST 小,AVL 树同时也是 BST,而 BST 不一定是 AVL 树。

AVL 树是由发明者的名字命名的,这个名字奇怪得一点都不奇怪。

AVL 树与一般 BST 的区别就是,它是平衡的,即左右子树的高度差不大于 1,且对于二叉树中的每个节点,这句话都是对的。

为了方便,AVL 树把左右子树的高度差存在了节点上,叫做平衡因子,平衡因子 = 左子树高度 - 右子树高度。如果平衡因子是除了 -1,0,1 之外的数字,说明以该节点为根节点的子树已经失去了平衡。

为什么平衡很重要呢

对于 BST,理想的查找/插入/删除操作的时间是 $O(logN)$ (N 是节点数),但如果二叉树退化到链表,操作时间就变成了 $O(N)$,AVL 树就是为了避免这种情况而存在的。AVL 树的查找/插入/删除时间一直是 $O(logN)$,为了保持这个时间,我们需要在进行插入/删除操作之后,再进行某项操作来维持 AVL 树的平衡,即将它的高度维持为 $logN$。

操作

插入

插入就和 BST 的插入操作是一样的,不过插入之后,需要原路返回找到第一个失去平衡的节点,对它进行旋转操作。只需要对以这个节点为根节点的子树进行旋转操作,整棵 AVL 树就会重新回归平衡。

要找到失去平衡的子树,需要判断节点的平衡因子。插入新节点后,一些节点平衡因子会改变,因此需要在插入新节点后,原路返回更新节点的平衡因子。

如果使用循环的方法插入新节点,那么在 AVL 树节点的设计上,还需要增加一个 parent 指针指向父节点,才能实现原路返回;如果使用递归的方法来插入新节点,递归本身就有一个原路返回的过程,所以 parent 指针也不需要了。

旋转

旋转就是用来维持 AVL 树平衡的操作。

假设 x 是进行插入操作后失去平衡的子树的根节点,那么在插入新节点时总共有 4 种可能发生的情况:

x 是插入新节点后原路返回时遇到的第一个失去平衡的节点,我们只需要关注这个节点。

  1. LL: 新节点作为 x 的左子节点的左子节点插入

  2. RR: 新节点作为 x 的右子节点的右子节点插入

  3. LR: 新节点作为 x 的左子节点的右子节点插入

  4. RL: 新节点作为 x 的右子节点的左子节点插入

对于这 4 种情况分别有不同的旋转策略:

  1. LL: 对 x 做右旋操作

  2. RR: 对 x 做左旋操作

  3. LR: 对 x 的左子节点做左旋操作,再对 x 做右旋操作

  4. RL: 对 x 的右子节点做右旋操作,再对 x 做左旋操作

这些策略就像魔方公式一样,记住就行。当然有兴趣也可以去看证明过程,我是暂时没这个兴趣啦。

如何判断插入是哪种情况:

TODO

删除

TODO

代码

TODO

复杂度

操作

时间

空间

插入

$O(logn)$

$O(1)$

删除

$O(logn)$

$O(1)$

旋转

$O(1)$

$O(1)$

可视化

AVL 树 vs 红黑树

AVL 树一般会拿来跟红黑树比较,两者都是平衡的二叉搜索树,不过它们采取不同的策略来保持树的平衡。AVL 树比红黑树平衡度更高,不过插入/删除操作后的需要的旋转操作也可能更多。

如果是查找操作居多,插入/删除操作较小,可以优先考虑 AVL 树。

如果插入/删除操作居多,应该优先考虑红黑树。

PreviousDSA - 哈希表NextDSA - 二叉树

Last updated 4 years ago

Was this helpful?

,可以看到插入/删除等操作的动态过程。

一个 AVL 树可视化网站
read this