考研数据结构通关秘籍 - 第五章 树与二叉树 核心考点与高频错题精讲
2026/7/15 2:05:37 网站建设 项目流程

1. 树与二叉树基础概念精讲

树结构是计算机科学中最重要的非线性数据结构之一,广泛应用于文件系统、数据库索引等领域。在考研数据结构中,树与二叉树章节占据约15%的分值比重,是必须掌握的核心内容。

树的定义可以类比现实中的家族树:有一个唯一的根节点(祖先),每个节点可以有多个子节点(后代),但只能有一个父节点(直接上级)。这种"一对多"的关系使得树特别适合表示层级关系。例如操作系统中的目录结构就是典型的树形应用。

二叉树是每个节点最多有两个子节点的特殊树结构。与普通树不同,二叉树严格区分左子树和右子树,即使只有一个子节点也必须明确其左右位置。这个特性使得二叉树在算法实现上更加规范。

常见易错点

  • 混淆"度为m的树"与"m叉树":前者至少有一个节点度为m,后者所有节点度≤m
  • 忽略二叉树是有序树:交换左右子树会得到不同的二叉树
  • 计算结点数时漏算根节点:总节点数=总度数+1(根节点没有父节点)

2. 二叉树核心性质与计算技巧

2.1 特殊二叉树特征对比

类型节点特征层序编号规则应用场景
满二叉树所有非叶节点度为2,叶子全在最底层i的左孩子2i,右孩子2i+1堆结构基础
完全二叉树仅最后两层有叶子,且左对齐同满二叉树优先队列实现
二叉排序树左<根<右的有序关系无固定规则动态查找系统
平衡二叉树任意节点左右子树高度差≤1通过平衡因子调整数据库索引

完全二叉树的性质在考研中频繁出现:

  • 当n为偶数时,有1个度为1的节点(且必为左孩子)
  • 分支节点与叶节点的分界点是⌊n/2⌋
  • 高度为h的完全二叉树至少2^(h-1)个节点,至多2^h-1个节点

真题示例: 已知完全二叉树第6层有8个叶子,求最少节点数。 解:前5层满节点=31,第6层8叶说明第5层有⌈8/2⌉=4个非叶节点,总节点=31+4+8=43

2.2 遍历序列还原二叉树

二叉树的遍历是考试重点,三种遍历方式的非递归实现需要熟练掌握。更关键的是根据遍历序列还原二叉树:

必须包含中序序列才能唯一确定二叉树形态。解题步骤:

  1. 用前序/后序的第一个/最后一个元素确定根节点
  2. 在中序序列中找到根的位置,划分左右子树
  3. 递归处理左右子树

高频错题: 已知前序ABDECFG,中序DBEAFCG,求后序。 解:A为根,左子树(DBE)右子树(FCG)→左子树前序BDE→B为根→D左E右→右子树前序CFG→C为根→F左G右→后序DEBFGCA

3. 线索二叉树实战解析

3.1 线索化原理

普通二叉树存在大量空指针域(n个节点有n+1个空链域),线索化利用这些空域存储遍历顺序中的前驱后继信息。通过增加两个标志位:

  • ltag=0时lchild指向左孩子,1时指向前驱
  • rtag=0时rchild指向右孩子,1时指向后继

中序线索化代码实现

void InThread(ThreadTree p, ThreadTree &pre) { if(p) { InThread(p->lchild, pre); // 递归左子树 if(!p->lchild) { // 左子树为空建立前驱线索 p->lchild = pre; p->ltag = 1; } if(pre && !pre->rchild) { // 前驱节点右子树为空建立后继线索 pre->rchild = p; pre->rtag = 1; } pre = p; // 更新pre指针 InThread(p->rchild, pre); // 递归右子树 } }

3.2 线索二叉树的遍历

线索二叉树的最大优势是可以直接找到前驱后继,无需递归栈:

找中序后继

ThreadNode *NextNode(ThreadNode *p) { if(p->rtag == 1) return p->rchild; // 直接返回线索 else { p = p->rchild; // 进入右子树 while(p->ltag == 0) // 找最左下节点 p = p->lchild; return p; } }

易错警示

  • 先序线索二叉树中找前驱需要知道父节点指针(普通线索无法实现)
  • 后序线索二叉树中找后继同样需要父节点信息
  • 中序线索是唯一能同时方便找前驱后继的情况

4. 树与森林的转换技巧

4.1 存储结构对比

存储方式优点缺点适用场景
双亲表示法找父节点快O(1)找孩子需要遍历并查集实现
孩子表示法找孩子方便找父节点困难需要频繁查询子节点
孩子兄弟表示法树与二叉树转换的桥梁找父节点需额外处理森林与二叉树转换

孩子兄弟表示法(二叉树表示法)是最重要的存储方式:

  • firstchild相当于二叉树的左孩子
  • nextsibling相当于二叉树的右孩子
  • 这种表示法使得树和二叉树的算法可以相互转换

4.2 森林与二叉树转换

转换规则:

  1. 每棵树的根节点作为二叉树的根
  2. 树中节点的第一个孩子作为二叉树的左孩子
  3. 树中节点的右兄弟作为二叉树的右孩子

重要性质

  • 森林的先序遍历序列 = 对应二叉树的先序序列
  • 森林的后序遍历序列 = 对应二叉树的中序序列(注意不是后序!)

5. 高频考点:平衡二叉树调整

平衡二叉树(AVL树)的调整是每年必考大题,需要掌握四种旋转场景:

5.1 失衡类型与调整

  1. LL型:在A的左孩子的左子树插入导致失衡

    • 右旋操作:将B作为根,A作为B的右孩子,BR作为A的左孩子
  2. RR型:在A的右孩子的右子树插入导致失衡

    • 左旋操作:将B作为根,A作为B的左孩子,BL作为A的右孩子
  3. LR型:在A的左孩子的右子树插入导致失衡

    • 先左旋后右旋:先对C左旋变成LL型,再整体右旋
  4. RL型:在A的右孩子的左子树插入导致失衡

    • 先右旋后左旋:先对C右旋变成RR型,再整体左旋

记忆口诀: "LL右旋,RR左旋,LR先左后右,RL先右后左"

5.2 平衡二叉树插入示例

插入序列:{15, 3, 7, 10, 9, 8}

  1. 插入15和3后正常
  2. 插入7时节点15失衡(LR型):
    • 先对3左旋:3作为7的左孩子
    • 再对15右旋:7作为根,3左15右
  3. 插入10后无失衡
  4. 插入9时节点15失衡(RL型):
    • 先对10右旋:10作为9的右孩子
    • 再对15左旋:9作为根,7左15右
  5. 插入8时节点9失衡(LR型):
    • 先对7左旋:7作为8的左孩子
    • 再对9右旋:8作为根,7左9右

6. 哈夫曼树与编码实战

哈夫曼树是带权路径长度(WPL)最小的二叉树,用于数据压缩:

构建步骤

  1. 将所有权值作为单独的树
  2. 每次选取权值最小的两棵树合并,新树权值为两者之和
  3. 重复直到只剩一棵树

真题技巧

  • 哈夫曼树没有度为1的节点(n个叶子共有2n-1个节点)
  • 权值小的节点路径更长
  • 同一组权值可能生成不同形态的哈夫曼树,但WPL相同

编码实现

typedef struct { int weight; int parent, lch, rch; } HTNode; void CreateHuffmanTree(HTNode ht[], int n) { for(int i=1; i<=2*n-1; ++i) ht[i] = {0,0,0,0}; for(int i=1; i<=n; ++i) cin >> ht[i].weight; for(int i=n+1; i<=2*n-1; ++i) { int s1, s2; Select(ht, i-1, s1, s2); // 选择两个最小权值 ht[i].weight = ht[s1].weight + ht[s2].weight; ht[s1].parent = ht[s2].parent = i; ht[i].lch = s1; ht[i].rch = s2; } }

在最后的冲刺阶段,建议每天手写一遍二叉树的非递归遍历代码,并完成2-3道平衡二叉树调整的练习题。对于线索二叉树,要重点理解不同遍历顺序下前驱后继的查找逻辑差异。实际编程时,树的深度优先搜索与二叉树遍历有诸多相似之处,这种触类旁通的能力正是考研考察的重点。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询