首页/数据结构/04-tree/树和森林 🔗 在 Obsidian 中打开
数据结构 · 04-tree

树和森林

重要度 ⭐⭐⭐⭐ 森林存储结构转换遍历
速查
树→二叉树口诀:左孩子右兄弟。遍历对应:树的先根 = 二叉树先序;树的后根 = 二叉树中序(高频考点)。森林→二叉树:各树根用右指针相连。

核心概念

一、树的存储结构

1. 双亲表示法:用数组存储,每个结点记录双亲位置。找双亲 $O(1)$,找孩子需遍历 $O(n)$。

typedef struct { ElemType data; int parent; } PTNode;   // parent = 双亲下标
typedef struct { PTNode nodes[MaxSize]; int n; } PTree;

2. 孩子表示法:每个结点用链表存储所有孩子。找孩子方便,找双亲需遍历。

typedef struct CTNode { int child; struct CTNode *next; } CTNode;
typedef struct { ElemType data; CTNode *firstchild; } CTBox;   // 孩子链表头
typedef struct { CTBox nodes[MaxSize]; int n, r; } CTree;      // r = 根位置

3. 孩子兄弟表示法(二叉链表):找第一个孩子 $O(1)$、找下一个兄弟 $O(1)$,可转换为二叉树。

typedef struct CSNode {
    ElemType data;
    struct CSNode *firstchild, *nextsibling;  // 第一个孩子、右兄弟
} CSNode, *CSTree;
         A
       / | \           孩子兄弟表示:
      B  C  D          A → firstchild → B → nextsibling → C → nextsibling → D
     / \                                    ↓
    E   F                                   E → nextsibling → F

二、树、森林与二叉树的转换

树 → 二叉树(左孩子右兄弟)

  1. 所有兄弟结点之间加连线
  2. 对每个结点只保留与第一个孩子的连线
  3. 以树根为轴心顺时针旋转 45°

二叉树 → 树(逆过程):加线(左孩子的右链逐级连回父)、去线(删除所有右孩子连线)、层次调整。

森林 → 二叉树:先将每棵树转为二叉树,再把各树根视为兄弟用右指针连接。

三、树的遍历

  • 先根遍历:先访问根,再遍历各子树 —— 等价于二叉树先序遍历
  • 后根遍历:先遍历各子树,再访问根 —— 等价于二叉树中序遍历
  • 层次遍历:从上到下、从左到右,用队列
注意树的后根遍历 ≠ 二叉树的后序遍历!后根遍历对应二叉树的中序遍历。

森林遍历:先序遍历(访问第一棵根→子树→剩余森林)等价二叉树先序;中序遍历等价二叉树中序

手算示例

例 1:树转二叉树

         A
       / | \
      B  C  D
     / \
    E   F
  1. 加兄弟连线:B-C、C-D、E-F
  2. 保留左孩子:A-B、B-E
  3. 旋转 45° → 得:
         A
        /
       B
      / \
     E   C
      \   \
       F   D

例 2:森林转二叉树

树1: A        树2: G
    / \            |
   B   C           H

各树先转二叉树,再把根 A 和 G 用右指针连接。

A → G
|   |
B   H
 \
  C

例 3:遍历对应

遍历方式结果
树先根A B C D
树后根B C D A
对应二叉树先序A B C D
对应二叉树中序B C D A

常见考法

考法 1给出树,画出对应的二叉树(左孩子右兄弟)。
考法 2问:树的后根遍历对应二叉树的什么遍历?答:中序遍历
考法 3给出森林,写出先序和中序遍历序列。
考法 4孩子兄弟表示法中,firstchild 和 nextsibling 分别指向什么?答:第一个孩子和下一个兄弟。

易错点

易错清单
  1. 树的后根遍历 = 二叉树的中序遍历:不是后序!
  2. 森林先序遍历:先访问每棵树的根,再遍历子树。
  3. 左孩子右兄弟:这是转换的核心规则。
  4. 兄弟连线要删除:转换回树时要去掉兄弟连线。
  5. 森林转二叉树:树根之间是右指针关系。

核心结论

存储方式找双亲找孩子空间
双亲表示O(1)O(n)n 个结点
孩子表示O(n)O(1)n + 边数
孩子兄弟O(n)O(1)2n 指针
遍历对应(必背)树的先根 = 二叉树先序;树的后根 = 二叉树中序。森林的先序/中序分别对应二叉树的先序/中序。

记忆卡片

树转二叉树的规则?
左孩子右兄弟:加兄弟连线 → 保留左孩子 → 旋转 45°。
树的后根遍历对应二叉树?
中序遍历(不是后序)。
孩子兄弟表示找第一个孩子?
O(1),通过 firstchild 直接取得。
森林转二叉树各树根怎么连?
用右指针连接(视为兄弟)。

交互动画 · 树 → 二叉树(左孩子右兄弟)

A B C D E F 原始树:A 的孩子 B、C、D;B 的孩子 E、F
① 给所有兄弟结点(B-C、C-D、E-F)加连线
点①→②→③ 观察树如何变为二叉树(左孩子右兄弟)
观察点:加兄弟线(紫)→ 保留第一孩子(A-B、B-E)→ 其余 A-C、A-D、B-F 淡化 → 成二叉树。

相关知识点

binary-tree-storage union-find forest-to-binary-tree

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。