数据结构(7)
目录
一、树的遍历
1、先序遍历
(1)定义
(2)核心逻辑
(3)示例说明
(4)特点
2、后序遍历
(1)定义
(2)核心逻辑
(3)示例说明
(4)特点
二、森林的遍历
1、先序遍历
(1)定义
(2)核心步骤(递归定义)
(3)示例说明
(4)特点
2、中序遍历
(1)定义
(2)核心步骤(递归定义)
(3)示例说明
(4)特点
三、树的表示形式
1、嵌套集合
2、广义表的形式表示
3、凹入表示法
4、左孩子——右兄弟表示法
一、树的遍历
1、先序遍历
介绍:访问根,依次先序访问根结点的每棵子树
(1)定义
先序遍历是树的一种深度优先遍历方式,遵循 “先访问根节点,再依次对根节点的每棵子树进行先序遍历” 的规则。
(2)核心逻辑
- 第一步:访问当前根节点(如输出节点值、记录节点信息等)。
- 第二步:按子树的顺序(通常从左到右),依次对每棵子树执行先序遍历(递归应用上述规则)。
(3)示例说明
假设有如下树结构(根节点 A 有 3 棵子树,子树根分别为 B、C、D;B 有 1 棵子树 E):
A/ | \B C D/E
遍历过程:
- 访问根节点 A → 结果:[A]。
- 对 A 的第一棵子树(根为 B)执行先序遍历:
- 访问 B → 结果:[A, B]。
- 对 B 的子树(根为 E)执行先序遍历:
- 访问 E → 结果:[A, B, E]。
- E 无其他子树,返回。
- 对 A 的第二棵子树(根为 C)执行先序遍历:
- 访问 C → 结果:[A, B, E, C]。
- C 无其他子树,返回。
- 对 A 的第三棵子树(根为 D)执行先序遍历:
- 访问 D → 结果:[A, B, E, C, D]。
- D 无其他子树,返回。
最终先序遍历序列:A → B → E → C → D。
(4)特点
- 遍历顺序体现 “根优先”,先处理当前节点,再深入子树。
- 适用于需要 “先获取根节点信息,再处理子树” 的场景(如复制树、统计树的节点总数)。
2、后序遍历
介绍:依次访问根结点的每棵子树通过后序遍历,再访问根
(1)定义
后序遍历是树的另一种深度遍历方式,遵循 “先依次对根节点的每棵子树进行后序遍历,最后访问根节点” 的规则。
(2)核心逻辑
- 第一步:按子树的顺序(通常从左到右),依次对每棵子树执行后序遍历(递归应用上述规则)。
- 第二步:访问当前根节点(如输出节点值、记录节点信息等)。
(3)示例说明
使用与先序遍历相同的树结构:
A/ | \B C D/E
遍历过程:
- 对 A 的第一棵子树(根为 B)执行后序遍历:
- 对 B 的子树(根为 E)执行后序遍历:
- E 无其他子树,访问 E → 结果:[E]。
- 访问 B → 结果:[E, B]。
- 对 B 的子树(根为 E)执行后序遍历:
- 对 A 的第二棵子树(根为 C)执行后序遍历:
- C 无其他子树,访问 C → 结果:[E, B, C]。
- 对 A 的第三棵子树(根为 D)执行后序遍历:
- D 无其他子树,访问 D → 结果:[E, B, C, D]。
- 访问根节点 A → 结果:[E, B, C, D, A]。
最终后序遍历序列:E → B → C → D → A。
(4)特点
- 遍历顺序体现 “子树优先”,先深入所有子树并处理完毕,再返回处理当前节点。
- 适用于需要 “先处理完所有子树,再基于子树结果处理根节点” 的场景(如计算树的深度、释放树的内存)。
树没有中序遍历,因子树不分左右
问:若采用“先转换,后遍历”方式,结果如何?
(1)树的先序遍历二法相同
(2)树的后序遍历相当于对应二叉树的中序遍历
(3)树无后序遍历
二、森林的遍历
1、先序遍历
若森林为空,返回;访问第一棵树的根节点;先序遍历第一棵树中根节点的子树森林;先序遍历除去第一棵树之后还剩余的树构成的森林
(1)定义
森林的先序遍历遵循 “先访问第一棵树的根,再深入处理第一棵树的子树,最后遍历剩余森林” 的规则,本质是对森林中每棵树进行 “先根” 访问,并保持树的顺序。
(2)核心步骤(递归定义)
- 若森林为空,直接返回(遍历结束)。
- 访问当前森林中第一棵树的根节点(优先处理根)。
- 先序遍历第一棵树的根节点的子树森林(将第一棵树的所有子树视为一个新森林,递归先序遍历)。
- 先序遍历除去第一棵树后剩余的森林(处理完第一棵树后,按同样规则遍历剩下的树)。
(3)示例说明
假设有如下森林(包含 2 棵树):
- 树 1:根 A,子树森林为 {B, C}(B 是 A 的第一个子树,C 是 B 的兄弟子树);B 有子树 D。
- 树 2:根 E,子树森林为 {F}(F 是 E 的子树)。
森林结构示意:
树1: A/ \B C/D树2: E/F
遍历过程:
- 访问第一棵树的根 A → 结果:[A]。
- 先序遍历 A 的子树森林({B, C}):
- 访问子树森林中第一棵树的根 B → 结果:[A, B]。
- 先序遍历 B 的子树森林({D}):
- 访问 D → 结果:[A, B, D]。
- D 无子树,返回。
- 先序遍历除去 B 后剩余的子树森林({C}):
- 访问 C → 结果:[A, B, D, C]。
- C 无子树,返回。
- 先序遍历除去第一棵树后剩余的森林({树 2}):
- 访问树 2 的根 E → 结果:[A, B, D, C, E]。
- 先序遍历 E 的子树森林({F}):
- 访问 F → 结果:[A, B, D, C, E, F]。
- F 无子树,返回。
最终先序遍历序列:A → B → D → C → E → F。
(4)特点
- 遍历顺序体现 “根优先、树顺序优先”:先访问每棵树的根,再处理其内部子树,且严格按森林中树的先后顺序遍历。
- 与森林转化为二叉树后的先序遍历结果完全一致(因二叉树的先序遍历也是 “根→左子树→右子树”,对应 “根→子树森林→剩余森林”)。
2、中序遍历
若森林为空,返回;中序遍历森林中第一棵树的根节点的子树森林;访问第一棵树的根节点;中序遍历除去第一棵树之后剩余的树构成的森林
(1)定义
森林的中序遍历遵循 “先处理第一棵树的子树,再访问第一棵树的根,最后遍历剩余森林” 的规则,本质是对森林中每棵树进行 “先子树后根” 的访问,并保持树的顺序。
(2)核心步骤(递归定义)
- 若森林为空,直接返回(遍历结束)。
- 中序遍历当前森林中第一棵树的根节点的子树森林(先深入处理第一棵树的所有子树)。
- 访问第一棵树的根节点(子树处理完毕后再访问根)。
- 中序遍历除去第一棵树后剩余的森林(处理完第一棵树后,按同样规则遍历剩下的树)。
(3)示例说明
使用与先序遍历相同的森林结构:
遍历过程:
- 中序遍历第一棵树(A)的子树森林({B, C}):
- 中序遍历 B 的子树森林({D}):
- D 无子树,直接返回(无访问)。
- 访问 B → 结果:[B]。
- 中序遍历除去 B 后剩余的子树森林({C}):
- C 无子树,直接返回。
- 访问 C → 结果:[B, C]。
- 中序遍历 B 的子树森林({D}):
- 访问第一棵树的根 A → 结果:[B, C, A]。
- 中序遍历除去第一棵树后剩余的森林({树 2}):
- 中序遍历 E 的子树森林({F}):
- F 无子树,直接返回。
- 访问 E → 结果:[B, C, A, E]。
- (F 的子树森林为空,无需额外操作)。
- 中序遍历 E 的子树森林({F}):
最终中序遍历序列:B → C → A → F → E??? (修正:步骤 3 中,E 的子树森林是 {F},中序遍历 F 的子树森林(空)→ 访问 F → 再访问 E,因此正确过程为:3. 中序遍历树 2 的子树森林({F}):
- F 无子树,返回 → 访问 F → 结果:[B, C, A, F]。
- 访问 E → 结果:[B, C, A, F, E]。
最终正确中序序列:B → C → A → F → E。
(4)特点
- 遍历顺序体现 “子树优先、树顺序优先”:先处理每棵树的所有子树,再访问其根,且严格按森林中树的先后顺序遍历。
- 与森林转化为二叉树后的中序遍历结果完全一致(因二叉树的中序遍历是 “左子树→根→右子树”,对应 “子树森林→根→剩余森林”)。
问:若采用“先转换,后遍历”方式,结果是否相同?
森林的先序和中序遍历在两种方式下的结果相同,但森林的后序遍历则不一定
三、树的表示形式
1、嵌套集合
- 用集合的嵌套关系模拟树的层次:根节点对应最外层集合,子节点对应内层集合,且任意两个集合要么完全分离,要么一个包含另一个。
- 示例:树 A 包含 B 和 C,B 包含 D,则表示为 {A, {B, {D}}, {C}} 。
- 特点:直观体现 “父子包含” 关系,适合抽象描述,但不便于计算机存储和操作。
2、广义表的形式表示
- 用广义表(可嵌套的列表)表示:根节点作为表名,后跟由子树组成的广义表。
- 示例:同上树表示为 A (B (D), C) ,其中 A 是根,B (D) 和 C 是子树(B 的子树为 D)。
- 特点:结构紧凑,既体现根与子树的关系,又保留子树的顺序,便于人工读写和转换为代码结构(如链表)。
3、凹入表示法
- 类似书籍目录的缩进形式:根节点顶格,子节点缩进,层级越深缩进越多,同一父节点的子节点缩进量相同。
- 示例:
ABDC - 特点:视觉直观,适合手动绘制和阅读,但不便于计算机处理(难以解析层级关系)。
4、左孩子——右兄弟表示法
- 用二叉树结构存储:每个节点包含 “左指针”(指向第一个子节点)和 “右指针”(指向相邻兄弟节点)。
- 示例:树 A 的左指针指向 B(第一个子节点),B 的右指针指向 C(兄弟节点),B 的左指针指向 D(B 的子节点)。
- 特点:将多叉树转为二叉树,统一数据结构,可直接复用二叉树的算法(如遍历),是计算机中最常用的树存储方式。
