Skip to content

2.5 树和二叉树

计算机程序设计 · 数据结构 · 2.5 树和二叉树

树和二叉树 ⭐

🎯 一句话秒杀:树是一对多的层次结构,二叉树是最常用的树(每个结点最多俩孩子)。遍历二叉树就是按特定顺序访问每个结点一次


一、树的基本概念

树的定义

树 = n(n≥0)个结点的有限集合。n=0时为空树。 有且只有一个根结点,其余结点分成m个互不相交的子树。

树的基本术语

术语定义
唯一没有前驱的结点
叶子没有孩子的结点(度为0)
结点度结点拥有的子树个数
树的度所有结点度的最大值
深度/高度从根到叶子最大层数(根为第1层)
森林m棵互不相交的树的集合

二、二叉树

二叉树的定义与性质

二叉树每个结点最多有2棵子树(左子树和右子树),分左右,顺序不能颠倒

重要性质(必背!):

  1. 第 i 层最多有 2^(i-1) 个结点(i≥1)
  2. 深度为 k 的二叉树最多有 2^k - 1 个结点
  3. 叶子结点数 n₀ = 度为2的结点数 n₂ + 1
  4. n个结点的二叉树深度至少为 ⌊log₂n⌋ + 1

特殊二叉树

类型定义特点
满二叉树每一层都满结点总数 = 2^k - 1
完全二叉树只有最后一层不满,且从左向右连续可用顺序存储
二叉排序树左<根<右中序是递增序列
平衡二叉树左右子树高度差≤1查找效率 O(log n)

🔑 秒杀秘籍

性质3 叶子数公式: 叶子 = 度为2的结点 + 1(n₀ = n₂ + 1) 考试必考:已知二叉树度2结点有5个,叶子有___个? → 6个

三、二叉树的存储

顺序存储(数组)

c
// 完全二叉树用数组存
// 根下标1,左孩子2i,右孩子2i+1
int tree[MAXSIZE];
// tree[1] = 根, tree[2] = 左孩子, tree[3] = 右孩子...

完全二叉树顺序存储映射:父 i → 左 2i 右 2i+1

链式存储(最常用)

c
typedef struct BiTNode {
    int data;                 // 数据域
    struct BiTNode *lchild;   // 左孩子指针
    struct BiTNode *rchild;   // 右孩子指针
} BiTNode, *BiTree;
        A
      /   \
     B     C
    / \   / \
   D   E F   G

链式存储结构:
     A(•, •)
    /       \
  B(•, •)   C(•, •)
  /    \    /    \
D(•,•) E(•,•) F(•,•) G(•,•)

四、二叉树的遍历(绝对重点!)

三种遍历方式

c
// 先序遍历:根 → 左 → 右
void PreOrder(BiTree T) {
    if (T == NULL) return;
    printf("%d ", T->data);   // 访问根
    PreOrder(T->lchild);      // 遍历左子树
    PreOrder(T->rchild);      // 遍历右子树
}

// 中序遍历:左 → 根 → 右
void InOrder(BiTree T) {
    if (T == NULL) return;
    InOrder(T->lchild);
    printf("%d ", T->data);
    InOrder(T->rchild);
}

// 后序遍历:左 → 右 → 根
void PostOrder(BiTree T) {
    if (T == NULL) return;
    PostOrder(T->lchild);
    PostOrder(T->rchild);
    printf("%d ", T->data);
}

遍历结果示例

        A
      /   \
     B     C
    / \   / \
   D   E F   G

先序:A B D E C F G   (根左右)
中序:D B E A F C G   (左根右)
后序:D E B F G C A   (左右根)

二叉树三种遍历顺序图(数字为访问顺序)

📌 图里圆圈内的数字是访问顺序:先序先访问根(A=1),中序先访问最左(D=1),后序最后访问根(A=7)。背口诀:先序"根左右"、中序"左根右"、后序"左右根",配合上图理解递归遍历的推进方向。

🚨 红牌警告

已知中序+先序/后序 → 可唯一确定一棵二叉树只知道先序+后序 → 不能唯一确定! 考试必考:给你先序和中序,画出二叉树

五、线索二叉树

利用空指针域指向遍历序列的前驱/后继

  • 如果结点无左孩子 → lchild指向前驱
  • 如果结点无右孩子 → rchild指向后继

六、树的存储结构

表示法说明
双亲表示法每个结点存parent下标
孩子表示法每个结点存孩子链表
孩子兄弟表示法left=第一个孩子,right=下一个兄弟

孩子兄弟表示法可以将任意树转为二叉树!

七、哈夫曼树(最优二叉树)

定义

带权路径长度(WPL)最小的二叉树 WPL = ∑(叶子权重 × 路径长度)

构造哈夫曼树

  1. 所有结点看成独立的树(森林)
  2. 选两个权值最小的合并
  3. 新结点权值 = 两子权值和
  4. 重复2-3直到只剩一棵树
示例:权值 {2, 3, 5, 7}
合并2+3=5 → {5, 5, 7}
合并5+5=10 → {10, 7}
合并10+7=17 → {17}

哈夫曼树构造过程与编码(左0右1,WPL=32)

哈夫曼编码

  • 左分支标0,右分支标1
  • 从根到叶子路径上的0/1序列就是字符编码
  • 前缀编码:任何字符的编码都不是另一个的前缀

🔑 秒杀秘籍

哈夫曼树的特点:

  1. 权值越大的叶子离根越近
  2. 没有度为1的结点
  3. n个叶子 → 总结点数 = 2n - 1

📝 闭卷真题挑战

(点击下方空白查看答案)

1. 二叉树第i层最多有几个结点?

2. 深度为5的二叉树最多有几个结点?

3. 某二叉树有5个度为2的结点,叶子有几个?

4. 先序ABDCE,中序BDAEC,画出二叉树。

5. 哈夫曼树中n个叶子,总共有几个结点?
👆 点击展开答案
  1. **2^(i-1)**个
  2. 2^5-1 = 31
  3. n₀ = n₂ + 1 = 6
    A
   / \
  B   C
 /   /
D   E

思路:先序第一个A是根,中序A左边是左子树(B D),右边是右子树(E C)...

  1. 2n - 1个(哈夫曼树没有度为1的结点)

📖 教材习题对照

教材习题知识点难度
习题6.1~6.3二叉树性质⭐⭐
习题6.4~6.7二叉树遍历⭐⭐⭐
习题6.8~6.10树与二叉树的转换⭐⭐⭐
习题6.11~6.13哈夫曼树与哈夫曼编码⭐⭐⭐⭐

对应教材:严蔚敏《数据结构》C语言版 第2版 → 第6章 树和二叉树 对应考试大纲:考点16 — 树和二叉树

📺 配套视频

复习到本考点 → 先看视频补讲,再刷上面「闭卷挑战」。

仅供个人学习 · 考生回忆版 · 非考试院原卷