
本文详解Python中自平衡二叉搜索树(如AVL树)在插入序列 [80, 3, 20, 95, 70] 后根节点为何变为 20,阐明LR旋转机制、手动推演过程,并提供可验证的完整实现示例。
本文详解python中自平衡二叉搜索树(如avl树)在插入序列 `[80, 3, 20, 95, 70]` 后根节点为何变为 `20`,阐明lr旋转机制、手动推演过程,并提供可验证的完整实现示例。
在自平衡二叉搜索树(如AVL树)中,根节点不等于首个插入值,而是由插入顺序与平衡旋转共同决定的最终稳定结构的中心节点。你观察到 print(ST) 输出的根为 20 而非 80,这并非bug,而是AVL树严格维持平衡因子(左右子树高度差 ≤ 1)所触发的LR旋转(Left-Right Rotation)的必然结果。
下面以插入序列 [80, 3, 20, 95, 70] 为例,逐步还原关键步骤:
插入 80 → 树仅含根节点:80
-
插入 3 → 作为左孩子:
80 / 3
-
插入 20 → 比 3 大,插入至 3 的右子树:
80 / 3 \ 20此时节点 3 的右子树高度为 1,左子树为 0;而 80 的左子树高度升至 2,右子树为 0 → 平衡因子 = 2,失衡!
失衡点在 80,其左孩子 3 的右子树更深 → 符合 LR型失衡(先左后右),需执行 LR旋转:- 先对 3 进行 左旋(提升 20):
80 / 20 / 3
- 再对 80 进行 右旋(以 20 为新根):
20 / \ 3 80
✅ 此时树恢复平衡,20 成为新根。
- 先对 3 进行 左旋(提升 20):
继续插入 95 → 大于 20,进入 80 右子树 → 成为 80 的右孩子
插入 70 → 小于 80,大于 20 → 插入至 80 左子树,成为 70(无进一步失衡)
最终结构为:
20
/ \
3 80
/ \
70 95? 验证建议:不要依赖第三方未公开源码的 self_balancing_binary_search_tree 库(如问题中 line 297 所指)。推荐使用可调试的参考实现,例如基于AVL的轻量级版本:
class AVLNode:
def __init__(self, key):
self.key = key
self.left = self.right = None
self.height = 1
def get_height(node):
return node.height if node else 0
def get_balance(node):
return get_height(node.left) - get_height(node.right) if node else 0
def rotate_right(y):
x = y.left
T2 = x.right
x.right = y
y.left = T2
y.height = 1 + max(get_height(y.left), get_height(y.right))
x.height = 1 + max(get_height(x.left), get_height(x.right))
return x
def rotate_left(x):
y = x.right
T2 = y.left
y.left = x
x.right = T2
x.height = 1 + max(get_height(x.left), get_height(x.right))
y.height = 1 + max(get_height(y.left), get_height(y.right))
return y
def insert_avl(root, key):
if not root:
return AVLNode(key)
if key < root.key:
root.left = insert_avl(root.left, key)
elif key > root.key:
root.right = insert_avl(root.right, key)
else:
return root # no duplicates
root.height = 1 + max(get_height(root.left), get_height(root.right))
balance = get_balance(root)
# LR case: left-right → first left-rotate child, then right-rotate root
if balance > 1 and key > root.left.key:
root.left = rotate_left(root.left)
return rotate_right(root)
# RR case
if balance < -1 and key > root.right.key:
return rotate_left(root)
# LL case
if balance > 1 and key < root.left.key:
return rotate_right(root)
# RL case
if balance < -1 and key < root.right.key:
root.right = rotate_right(root.right)
return rotate_left(root)
return root
# 测试验证
root = None
for num in [80, 3, 20, 95, 70]:
root = insert_avl(root, num)
def inorder_print(node):
if node:
inorder_print(node.left)
print(node.key, end=' ')
inorder_print(node.right)
print("In-order traversal:", end=' '); inorder_print(root) # → 3 20 70 80 95
print(f"\nRoot is: {root.key}") # → Root is: 20✅ 运行结果明确输出 Root is: 20,印证了旋转逻辑的正确性。
关键提醒:
- 自平衡树的核心目标是保证查询/插入/删除时间复杂度稳定为 O(log n),而非保留插入顺序;
- 若需保持首元素为根(如构建静态BST),应禁用自动平衡或改用普通BST;
- 调试时优先打印中序遍历(验证BST性质)和树形结构(如用 graphviz 或层级打印),而非仅依赖 __str__ 实现——后者易受库内部格式影响。
掌握旋转类型(LL/LR/RR/RL)与触发条件,是理解和修复任何AVL实现问题的根本能力。

















