【算法考点】:二叉树基础 + 平衡树核心考点

189 阅读6分钟

一、二叉树基础:从定义到特殊类型

平衡树基于二叉树衍生,面试中常先考察基础概念 —— 需先掌握二叉树的定义、性质及特殊类型(满二叉树、完全二叉树)。

1. 二叉树的核心定义

二叉树是「每个节点最多有两个子节点」的树结构,子节点分左子树(Left)和右子树(Right),可递归定义为:

  • 空树,或
  • 由根节点、左二叉树、右二叉树组成(左 / 右子树也需满足二叉树定义)。

可视化:普通二叉树结构

image.png

2. 二叉树的 3 个高频性质(面试必背)

  1. 第 i 层最大节点数:若根为第 1 层,第 i 层最多有 2^(i-1) 个节点(如第 3 层最多 4 个);
  1. 高度 h 的最大节点数:总节点数最多为 2^h - 1(满二叉树即达到此上限);
  1. 叶子节点与度 2 节点关系:对任意非空二叉树,度为 0 的叶子节点数 n0 = 度为 2 的节点数 n2 + 1(推导:总边数 = 总节点数 - 1,且边数 = 2n2 +n1,联立得 n0=n2+1)。

3. 特殊类型:满二叉树(面试高频)

image.png

(1)满二叉树的定义

满二叉树是「除叶子节点外,所有节点均有两个子节点」的二叉树,且所有叶子节点在同一层

可视化:满二叉树结构(高度 h=3)

image.png

(2)满二叉树的 2 个关键公式(面试计算题常考)

  • 若高度为 h,总节点数 n = 2^h - 1 → 反推高度 h = log2(n+1);
  • 叶子节点数 n0 = 2^(h-1)(如 h=3 时,叶子数 = 4)。

(3)满二叉树 vs 完全二叉树(易混点辨析)

完全二叉树是「按层序填充,最后一层从左到右连续,中间不缺节点」的二叉树(可理解为 “满二叉树的前缀”),二者区别:

类型核心区别示例特征
满二叉树所有层均填满,叶子在同一层高度 3 时必 7 个节点
完全二叉树最后一层左连续,上层均填满高度 3 时可 5/6/7 个节点

可视化:完全二叉树(非满)

image.png

二、为什么需要平衡树?—— 从 BST 的问题说起

二叉搜索树(BST)是基于二叉树的有序结构,核心性质:左子树值<根<右子树值,中序遍历为有序序列。但BST 存在致命缺陷 —— 易退化

  • 当插入有序数据(如 1→2→3→4→5)时,BST 会退化为链表,此时查询 / 插入 / 删除时间复杂度从 O (logn) 暴跌至 O (n)。

可视化:BST 退化案例

平衡树的本质:在 BST 基础上增加「平衡约束」,通过自调整(旋转、颜色翻转等)维持树高为 O (logn),确保操作性能稳定。

三、面试高频平衡树 1:AVL 树(严格平衡)

AVL 树是最早的自平衡 BST,核心是「严格平衡约束」:

  • 每个节点的平衡因子(左子树高 - 右子树高)∈ {-1,0,1}
  • 树高严格控制在 O (logn),查找性能最优

AVL 树面试考点

  • 优点:查找快(树高最矮);缺点:插入 / 删除需多次旋转(维护严格平衡成本高)。
  • 应用场景:读多写少场景(如静态索引)。
  • 代码高频片段:平衡因子计算与旋转触发:
// 计算节点高度
private int getHeight(Node node) {
    return node == null ? 0 : node.height;
}
// 计算平衡因子
private int getBalance(Node node) {
    return node == null ? 0 : getHeight(node.left) - getHeight(node.right);
}
// 右旋实现(LL型处理)
private Node rightRotate(Node y) {
    Node x = y.left;
    Node T2 = x.right;
    // 旋转
    x.right = y;
    y.left = T2;
    // 更新高度
    y.height = Math.max(getHeight(y.left), getHeight(y.right)) + 1;
    x.height = Math.max(getHeight(x.left), getHeight(x.right)) + 1;
    return x; // 新根
}

四、面试高频平衡树 2:红黑树(近似平衡)

红黑树是工程中最常用的平衡树(如 Java TreeMap、Linux 内核),核心是「通过颜色规则维持近似平衡」,而非严格平衡因子。

1. 红黑树 5 条核心性质(面试必背)

  1. 每个节点非红即黑;
  1. 根节点是黑色;
  1. 叶子节点(NIL 空节点)是黑色;
  1. 红色节点的两个子节点必为黑色(无连续红节点);
  1. 从任意节点到其所有叶子的路径,黑色节点数相同(「黑高」一致)。

2. 红黑树 vs AVL 树(面试高频对比)

维度AVL 树红黑树
平衡程度严格(平衡因子 ±1)近似(黑高一致)
树高更矮(~1.44logn)略高(~2logn)
查找性能略优优秀(差距可忽略)
插入 / 删除成本高(需多次旋转)低(1-2 次旋转 + 颜色翻转)
工程应用读多写少场景通用场景(默认首选)

五、其他平衡树(面试速记)

1. 伸展树(Splay Tree)

  • 核心:无平衡约束,通过「伸展操作」将最近访问节点移到根(利用局部性原理)。
  • 特点:均摊复杂度 O (logn),但最坏 O (n);实现简单(无需维护平衡因子 / 颜色)。
  • 应用:缓存系统(频繁访问的节点更快获取)。

2. 替罪羊树(Scapegoat Tree)

  • 核心:当子树大小超过父节点的 α 倍(α≈0.7),直接「重构子树」为完全平衡树(暴力但高效)。
  • 特点:插入 / 删除均摊 O (logn),实现比红黑树简单。

六、面试题实战(结合图解)

题 1:判断一棵二叉树是否为平衡树(LeetCode 110)

思路:后序遍历,计算每个节点的左右子树高度,同时检查平衡因子。

public boolean isBalanced(TreeNode root) {
    return getHeightAndCheck(root) != -1;
}
// 若平衡,返回高度;否则返回-1
private int getHeightAndCheck(TreeNode node) {
    if (node == null) return 0;
    int leftH = getHeightAndCheck(node.left);
    if (leftH == -1) return -1; // 左子树已失衡
    int rightH = getHeightAndCheck(node.right);
    if (rightH == -1) return -1; // 右子树已失衡
    // 检查当前节点平衡因子
    if (Math.abs(leftH - rightH) > 1) return -1;
    return Math.max(leftH, rightH) + 1;
}

题 2:满二叉树高度为 h,求叶子节点数(面试基础题)

解答:根据满二叉树公式,叶子节点数 = 2^(h-1)(如 h=3 时,叶子数 = 4)。

推导:满二叉树总节点数 = 2^h -1,且满二叉树中 n2 = n0 -1(二叉树通用性质),总节点数 = n0 +n1 +n2。因满二叉树无度 1 节点(n1=0),故 2^h -1 =n0 +0 +(n0-1) → 2n0=2^h → n0=2^(h-1)。

题 3:AVL 树插入后,如何确定旋转类型?

步骤

  1. 插入节点后,从插入点向上找「第一个平衡因子绝对值>1 的节点」(失衡根);
  1. 计算失衡根的左子树平衡因子(LL/LR)或右子树平衡因子(RR/RL);
    • 失衡根平衡因子>1(左子树高):
      • 左子树平衡因子>0 → LL 型(右旋);
      • 左子树平衡因子<0 → LR 型(先左旋左子,再右旋根);
    • 失衡根平衡因子<-1(右子树高):
      • 右子树平衡因子<0 → RR 型(左旋);
      • 右子树平衡因子>0 → RL 型(先右旋右子,再左旋根)。