目录
1.2. 完全二叉树 (Complete Binary Tree)
1. 普通二叉树结构
二叉树是计算机科学中最基础且重要的树形数据结构之一,非空时由根节点和两个不相交的子树(左子树和右子树)组成。树中每个节点(包括根节点)最多有两个子节点(称为左子节点和右子节点),普通二叉树无其他约束。
1.1. 常见术语
根节点(Root):最顶层的节点
叶子节点(Leaf):没有子节点的节点
内部节点:至少有一个子节点的节点
深度(Depth):从根节点到某一节点的边数
高度(Height):从根节点到最深叶子节点的边数
度(Degree):节点的子节点数(二叉树中最大为2)
1.2. 完全二叉树 (Complete Binary Tree)
定义:
完全二叉树是指除了最后一层外,其他各层节点数都达到最大值,并且最后一层的节点都连续集中在左侧的二叉树。
特点:
可以不完全填满,但空缺只能出现在最后一层的最右侧
高度为 h 的完全二叉树,节点数n满足:
2^(h-1) ≤ n < 2^h - 1
常用于堆的实现
可以用数组高效存储(按层序遍历顺序存储)
示例:
A
/ \
B C
/ \ /
D E F
1.3. 满二叉树 (Full Binary Tree)
定义:
满二叉树是指所有非叶子节点都有两个子节点,且所有叶子节点都在同一层的二叉树。
特点:
每一层的节点数都达到最大值
高度为h的满二叉树,节点总数为
2^h - 1
叶子节点数 = 非叶子节点数 + 1
严格平衡,是最"饱满"的二叉树形态
示例:
A
/ \
B C
/ \ / \
D E F G
我可以看到,满二叉树其实是完全二叉树的特例。
2. 特殊二叉树结构
2.1. 二叉搜索树 (BST)
定义:
对于树中的每个节点:
左子树所有节点的值 小于 该节点的值
右子树所有节点的值 大于 该节点的值
左右子树也分别是BST
没有键值相等的节点(通常定义)
特点:
中序遍历BST会得到一个升序排列的元素序列
查找效率取决于树的高度
平均时间复杂度:O(log n)
最坏情况(退化成链表):O(n)
示例:
2.1.1. BST 基本操作 - 查找
def search(root, val):
if not root or root.val == val:
return root
if val < root.val:
return search(root.left, val)
return search(root.right, val)
2.1.2. BST 基本操作 - 插入
def insert(root, val):
if not root:
return TreeNode(val)
if val < root.val:
root.left = insert(root.left, val)
elif val > root.val:
root.right = insert(root.right, val)
return root
2.1.3. BST 基本操作 - 删除
三种情况处理:
无子节点:直接删除
一个子节点:用子节点替代
两个子节点:用后继节点(右子树的最小值)或前驱节点(左子树的最大值)替代
def deleteNode(root, key):
if not root:
return None
if key < root.val:
root.left = deleteNode(root.left, key)
elif key > root.val:
root.right = deleteNode(root.right, key)
else:
if not root.left:
return root.right
if not root.right:
return root.left
# 找右子树的最小节点
temp = root.right
while temp.left:
temp = temp.left
root.val = temp.val
root.right = deleteNode(root.right, temp.val)
return root
2.2. 平衡二叉树 (AVL 树)
AVL树是最早发明的自平衡二叉搜索树,由G.M. Adelson-Velsky和E.M. Landis在1962年提出。
2.2.1. 基本概念
AVL树是一种严格平衡的二叉搜索树,它要求:
每个节点的左右子树高度差(平衡因子)的绝对值不超过1
如果插入或删除操作导致平衡因子绝对值大于1,则通过旋转操作重新平衡
2.2.2. 核心特性
平衡因子(Balance Factor):
对于任意节点,平衡因子 = 左子树高度 - 右子树高度
合法值:-1、0、1
高度平衡:
保证树的高度始终为O(log n)
查找、插入、删除操作的时间复杂度均为O(log n)
2.2.3. 平衡操作(旋转)
当插入或删除导致不平衡时,有四种旋转情况:
1. 左旋 (RR情况 - 右子树的右子树导致不平衡)
A (平衡因子=-2)
\
B (平衡因子=-1)
\
C
旋转后:
B
/ \
A C
2. 右旋 (LL情况 - 左子树的左子树导致不平衡)
A (平衡因子=+2)
/
B (平衡因子=+1)
/
C
旋转后:
B
/ \
C A
3. 左右旋 (LR情况)
A
/
B
\
C
先对B左旋,再对A右旋:
C
/ \
B A
4. 右左旋 (RL情况)
A
\
B
/
C
先对B右旋,再对A左旋:
C
/ \
A B
2.3. 红黑树
红黑树是一种广泛使用的自平衡二叉搜索树,它在1972年由Rudolf Bayer发明,被称为"对称二叉B树",后来由Leo J. Guibas和Robert Sedgewick在1978年完善并命名为红黑树。
2.3.1. 基本概念
红黑树通过以下规则保持平衡:
节点颜色:每个节点是红色或黑色
根节点:根节点必须是黑色
叶子节点:所有叶子节点(NIL节点,空节点)都是黑色
红色节点规则:红色节点的两个子节点都必须是黑色(即不能有连续的红色节点)
黑高一致:从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点(称为"黑高")
2.3.2. 核心特性
近似平衡:虽然不如AVL树严格平衡,但能保证最长路径不超过最短路径的两倍
高效操作:插入、删除和查找操作的时间复杂度都是O(log n)
旋转次数少:相比AVL树,红黑树在插入和删除时需要的旋转操作更少
2.3.3. 平衡操作
1. 插入操作
按照二叉搜索树规则插入新节点(初始设为红色)
检查并修复红黑树性质:
情况1:新节点是根节点 → 变为黑色
情况2:父节点是黑色 → 无需处理
情况3:父节点和叔节点都是红色 → 重新着色
情况4:父节点红而叔节点黑(或不存在)→ 旋转+重新着色
2. 删除操作
执行标准BST删除
如果删除的是红色节点,性质保持不变
如果删除的是黑色节点,需要通过旋转和重新着色来修复性质
旋转操作
红黑树使用两种基本旋转(与AVL树类似):
左旋:
P Q / \ / \ A Q → P C / \ / \ B C A B
右旋:
P Q / \ / \ Q C → A P / \ / \ A B B C
3. 总结
我们可以看到 AVL 树和红黑树其实是二叉搜索树的变种。AVL 和 红黑树的代码相对比较复杂,涉及复杂的旋转问题。具体的代码,将在之后的博文里讨论。