1 树
1.0 基本概念
树是n( n ≥ 0 n\geq0 n≥0)个结点的有限集合T。当n=0时,称为空树,当n>0时,该集合满足如下条件:
- 其中必有一个称为根(root)特定结点,没有直接前驱,但有零个或多个直接后继。
- 其余n-1个结点可以划分为m个互不相交的有限集 T 1 , T 2 , . . . , T m T_1,T_2,..., T_m T1,T2,...,Tm,其中 T i T_i Ti又是一棵树,称为根root的子树,每棵子树的根结点有且仅有一个前驱,但有零个或多个直接后继。
1.2 示意图
1.3 引申概念
序号 | 名词 | 描述 | 例证 |
---|---|---|---|
1 | 结点 | 包含一个数据元素及若干指向其他结点的分支信息 | A,B,…,N都是结点 |
2 | 节点的度 | 一个结点的子树个数称为此结点的度 | A结点有3个子树,度为3 |
3 | 叶节点 | 度为0的结点,即无后继结点,也称为终端结点 | K,L,M,N无后继,为叶结点 |
4 | 分支结点 | 度不为0的结点,也称为非终端结点 | B为分支结点 |
5 | 孩子结点 | 一个结点的直接后继称为该结点的孩子结点 | D的孩子结点为H,I,J |
6 | 双亲结点 | 一个结点的直接前驱称为该结点的双亲结点 | B,C,D的双亲结点为A |
7 | 兄弟结点 | 同一双亲结点的孩子结点之间称为兄弟结点 | B,C,D为兄弟结点,E,F为兄弟结点 |
8 | 祖先结点 | 一个结点的祖先结点是从根结点到该结点的路径上的所有结点 | E的祖先结点为B,A |
9 | 子孙结点 | 一个结点的直接后继和间接后继称为该结点的子孙结点 | B的子孙结点为E,F,K,L |
10 | 树的度 | 树中所有结点的度的最大值 | 上树的度为3,A和D度为3最大的分支数 |
11 | 结点的层次 | 从根结点开始定义,根结点的层次为1,根的直接后继的层次为2,依次类推 | A为1层,K为4层 |
12 | 树的高度(深度) | 树中所有结点的层次的最大值 | 树高为4 |
13 | 有序树 | 在树T中,如果各子树T_i之间是有先后次序的,则称为有序树 | |
14 | 森林 | m(m>=0)棵互不相交的树的集合,将一颗非空树的根结点删去,树就变成一个森林,反之,给森林增加一个统一的根结点,森林就变成一棵树 |
1.4 树的抽象数据类型
数据对象D:一个集合,该集合中所有元素具有相同的特性
数据关系R:若D为空集,则为空树,若D中仅含一个数据元素,则R为空集,否则R={H},H是如下的二元关系:
- 在D中存在唯一的称为根的数据元素root,在关系H下没有前驱;
- 除root外,D中每个节点在关系H下有且仅有一个前驱;
1.5 树的基本操作
序号 | 名词 | 描述 |
---|---|---|
1 | InitTree(Tree) | 将Tree初始化为一颗空树 |
2 | DestoryTree(Tree) | 销毁树Tree |
3 | CreateTree(Tree) | 创建树Tree |
4 | TreeEmpyt(Tree) | 若Tree为空,返回True,否则False |
5 | Root(Tree) | 返回树Tree的根 |
6 | Parent(Tree,x) | 树Tree存在,x是Tree中的某个结点,若x为非根结点,返回她的双亲,否则返回空 |
7 | FirstTree(Tree,x) | 树Tree存在,x是Tree中的某个结点,若x为非叶子结点,返回她的第一个孩子结点,否则返回空 |
8 | NextSibling(Tree,x) | 树Tree存在,x是Tree中某个结点,若x不是其双亲的最后一个孩子结点,返回x后面的下一个兄弟结点,否则返回空 |
9 | InsertChild(Tree,p,Child) | 树Tree存在,p指向Tree中某个结点,非空树Child与Tree不想交,将Child插入Tree中,做p所指向结点的子树 |
10 | DeleteChild(Tree,p,i) | 树Tree存在,p指向Tree中某个结点,1≤i≤d,d为p所指向结点的度,删除Tree中p指向结点的第i棵子树 |
11 | TraverseTree(Tree, Visit()) | 树Tree存在,Visit()是对结点进行访问的函数,按照某种次序对树Tree的每个结点调用Visit()函数访问一次且最多一次,若Visit()失败,则操作失败 |
2 二叉树
2.1 概念
满足以下两个条件的树型结构称为二叉树(Binary Tree)。
- 每个结点的度都不大于2
- 每个结点的孩子结点次序不能任意颠倒
2.2 二叉树结构
二叉树有如下4种结构:
2.3 基本操作
序号 | 名词 | 描述 |
---|---|---|
1 | Initiate(bt) | 将二叉树bt初始化为空二叉树 |
2 | Create(bt) | 创建一棵非空二叉树bt |
3 | Destroy(bt) | 销毁二叉树bt |
4 | Empty(bt) | 若二叉树bt为空,则返回True |
5 | Root(bt) | 求二叉树bt的根结点,若bt为空,则返回空 |
6 | Parent(bt) | 求双亲函数,求二叉树bt中结点x的双亲结点,若结点x是二叉树的根结点或二叉树中无结点x返回空 |
7 | LeftChild(bt,x) | 求左孩子,若结点x为叶子结点或x不在bt中,返回空 |
8 | RightChild(bt,x) | 求右孩子,若结点x为叶子结点,或x不在bt中,返回空 |
9 | Traverse(bt) | 遍历操作,按某个次序一次访问二叉树中的每个节点一次且仅一次 |
10 | Clear(bt) | 清楚操作,将二叉树bt置为空树 |
2.4 二叉树性质
- 二叉树的第i层上至多有 2 i − 1 2^{i-1} 2i−1个结点, i ≥ 1 i\geq1 i≥1;
- 深度为k的二叉树,最多有 2 k − 1 2^{k}-1 2k−1个结点;
- 对任意一颗二叉树T,若终端结点数为 n 0 n_0 n0,度数为2的结点数为 n 2 n_2 n2,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1
- 具有n个结点的完全二叉树深度为 log 2 n + 1 \log_2n+1 log2n+1;
- 满二叉树:深度为k且共有
2
k
−
1
2^k-1
2k−1个结点的二叉树,每层结点都是满的,即每层结点都具有最大结点数;
- 完全二叉树:除最后一层外,其余层均满;
2.5 二叉树存储结构
二叉树的结构是非线性的,每一个结点最多可有两个后继,二叉树有两种存储结构:顺序存储结构和链式存储结构.
2.5.1 顺序存储结构
用一组连续的存储单元来存放二叉树的数据元素.
- 顺序存储
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
- 单支树
对于一般的二叉树,必须按照完全二叉树的形式来存储,这样会造成空间的浪费,单支树是一个极端情况.
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
A | NULL | C | NULL | NULL | NULL | G | NULL | NULL | NULL | NULL | NULL | NULL | NULL | O |
2.5.2 链式存储结构
对于任意的二叉树来说,每个结点只有两个孩子,一个双亲结点,可以设计每个结点至少包括三个域:数据域,左孩子域和右孩子域.
2.5.3 三叉链表
2.6 二叉树的遍历与线索化
2.6.1 二叉树的遍历规定
按一定规律对二叉树中的每个结点进行访问且仅访问一次.二叉树结构如图2.5所示,现定义如下:
序号 | 指令 | 描述 |
---|---|---|
1 | L | 遍历左子树 |
2 | D | 访问根结点 |
3 | R | 遍历右子树 |
- 遍历规定
序号 | 指令 | 描述 |
---|---|---|
1 | DLR | 访问根,遍历左子树,遍历右子树 |
2 | DRL | 访问根,遍历右子树,遍历左子树 |
3 | LDR | 遍历左子树,访问根,遍历右子树 |
4 | LRD | 遍历左子树,遍历右子树,访问根 |
5 | RDL | 遍历右子树,访问根,遍历左子树 |
6 | RLD | 遍历右子树,遍历左子树,访问根 |
根据对根的访问顺序,分别规定先序遍历(先根遍历),中序遍历(对称遍历)和后序遍历;
序号 | 命令 | 描述 | 流程 |
---|---|---|---|
1 | DLR | 先序遍历 | 首先访问根结点,其次先序遍历左子树,最后先序遍历右子树,当遍历结点为空时,执行下一遍历动作,否则一直遍历本动作 |
2 | LDR | 中序遍历 | 首先中序遍历左子树,其次访问根结点,最后中序遍历右子树,当遍历结点为空时,执行下一遍历动作,否则一直遍历本动作 |
3 | LRD | 后序遍历 | 首先后序遍历左子树,其次后序遍历右子树,最后访问根结点,当遍历结点为空时,执行下一遍历动作,否则一直遍历本动作 |
2.6.2 遍历
- 说明
参数 | 说明 |
---|---|
L_a | A结点的左子树,且有分支,L表示左子树地址,a表示结点 |
R_a | A结点的右子树,且有分支,R表示右子树地址,b表示结点 |
R_bn | B结点的左子树,无分支,n表示null空 |
- 遍历结果
先序遍历DLR:
A ↦ B ↦ D ↦ F ↦ G ↦ C ↦ E ↦ H A\mapsto B\mapsto D \mapsto F \mapsto G\mapsto C \mapsto E\mapsto H A↦B↦D↦F↦G↦C↦E↦H
中序遍历LDR:
B ↦ F ↦ D ↦ G ↦ A ↦ C ↦ E ↦ H B\mapsto F\mapsto D \mapsto G \mapsto A\mapsto C \mapsto E\mapsto H B↦F↦D↦G↦A↦C↦E↦H
后序遍历LRD:
F ↦ G ↦ D ↦ B ↦ H ↦ E ↦ C ↦ A F\mapsto G\mapsto D \mapsto B \mapsto H\mapsto E \mapsto C\mapsto A F↦G↦D↦B↦H↦E↦C↦A - 遍历过程
先序遍历
【参考文献】
[1]https://wenku.baidu.com/view/57d26d1ab80d6c85ec3a87c24028915f804d84be.html?from=search
[2]https://wenku.baidu.com/view/c74bb0184693daef5ff73dc9.html?from=search