目录
1. AVL树(Adelson-Velsky and Landis Tree)
为什么需要树?
在现实世界中,数据常常不是一维的。比如公司组织架构、家谱、操作系统的文件系统……它们都存在「层级关系」。
那么,从信息最基本的构成来说,如何表示这种「一对多」和「嵌套式」的结构?
用图(Graph):抽象实体(节点)+ 它们之间的关系(边)
特殊的图——无环、连通、有根、层级明确的图,就是我们所说的:
🎄 树结构(Tree)
🌱 基本的树结构定义
什么是树?
-
一棵树是一个由节点组成的数据结构,满足:
-
有一个“根节点”
-
每个节点有 0 个或多个子节点
-
无环(无回路)
-
每个子节点只能有一个父节点
-
树的术语
名称 | 说明 |
---|---|
根节点(Root) | 树的最上层节点 |
子节点(Child) | 从某个节点派生出来的节点 |
父节点(Parent) | 指向某个子节点的节点 |
叶子节点(Leaf) | 没有任何子节点的节点 |
深度(Depth) | 从根节点到某节点的路径长度 |
高度(Height) | 从某节点到最深叶节点的路径长度 |
子树(Subtree) | 以某个节点为根的树 |
🌿 常见基本树的变体
1. 二叉树 Binary Tree
-
每个节点最多有两个子节点(左、右)
-
是所有高级树结构的基础
2. 满二叉树 Full Binary Tree
-
每个节点要么有两个子节点,要么是叶子节点
3. 完全二叉树 Complete Binary Tree
-
每一层都被填满,最后一层从左到右填满
4. 平衡二叉树 Balanced Binary Tree
-
任意节点左右子树高度差不超过 1
🌳 二叉搜索树(BST)
定义:
一个有序的二叉树结构
满足所有左子树上的节点值 < 根节点 < 所有右子树上的节点值
操作:
-
插入:从根开始递归查找插入点
-
查询:类似于二分查找,效率高
-
删除:三种情况(无子节点、一个子节点、两个子节点)
时间复杂度:
操作 | 最佳情况 | 最坏情况(退化为链表) |
---|---|---|
查找 | O(log n) | O(n) |
插入/删除 | O(log n) | O(n) |
❗问题:
-
如果连续插入有序数据:BST 会退化为链表,导致性能下降!
🌲 自平衡二叉搜索树
为了解决 BST 退化的问题,引入了自动保持平衡的机制,主要有两类代表:
1. AVL树(Adelson-Velsky and Landis Tree)
-
每个节点维护一个“平衡因子”= 左右子树高度差
-
超过 ±1 就进行旋转修复(左旋、右旋、左右旋、右左旋)
-
查找非常快,但插入/删除开销大(频繁旋转)
2. 红黑树(Red-Black Tree)
定义:
红黑树是一种自平衡的二叉搜索树,其每个节点多了一个“颜色属性”【红 或 黑】,并且满足以下五条性质:
🎯 五大性质(核心):
-
每个节点不是红就是黑
-
根节点是黑色
-
每个叶子节点(NIL 节点)是黑色
-
如果一个节点是红的,则它的子节点必须是黑的(不能有两个连续红节点)
-
从任一节点到其叶子节点的路径上,黑色节点的数量必须相同
操作原理(通过旋转和变色维护这五条规则):
-
插入:默认插入红色节点,可能破坏“连续红”或“黑高一致性”,通过:
-
情况分类(叔叔红/黑 + 父红)
-
局部旋转和变色修复
-
-
删除:更复杂,重点在维持黑高一致性
时间复杂度:
操作 | 时间复杂度 |
---|---|
查找 | O(log n) |
插入 | O(log n) |
删除 | O(log n) |
实际应用:
-
Java 的
TreeMap
/TreeSet
-
Linux CFS 调度器(完全公平调度)
-
C++ STL 中的
map
和set
红黑树 vs AVL 树
属性 | AVL 树 | 红黑树 |
---|---|---|
平衡性 | 更严格 | 较宽松 |
插入效率 | 较慢(频繁旋转) | 更快 |
查找效率 | 快(更平衡) | 略慢 |
删除效率 | 复杂 | 简化处理 |
实际应用 | 数据频繁查找场景 | 插入/删除频繁的系统结构 |