树结构是一种非线性结构,该结构中的一个数据元素可以有两个或两个以上的直接后继元素,可以用来描述客观世界中广泛存在的层次结构关系。
(一)树与二叉树的定义
1.树的定义
树是n(n>=0)
个结点的有限集合,当n=0
时称为空树。
在任一非空树中,有且仅有一个称为根的结点;其余结点可分为m(m>=0)
个互不相交的有限子集,每个子集又都是一棵树,并且称为根结点的子树。
树的定义是递归的,表明了树本身的固有特性,也就是一棵树由若干棵子树构成,而子树又由更小的子树构成。
对于树中某个结点,它最多只和上一层的一个结点有直接关系,与其下一层的多个结点由直接关系。
2.树的基本概念
树结构示意图- 双亲、孩子和兄弟。结点的子树的根称为该结点的孩子;该结点称为其子结点的双亲;具有相同双亲的结点互为兄弟。
- 结点的度。一个结点的子树的个数记为该结点的度。如上图所示:
A
的度为3
,B
的度为2
,C
的度为0
,D
的度为1
。 - 叶子结点。度为
0
的结点,也称为终端结点。上图中的E、F、C、G
都是叶子结点。 - 内部结点。度不为
0
的结点,也称为分支结点或非终端结点。上图中的B、D
都是内部结点。 - 结点的层次。根为第一层,根的孩子在第二层,以此类推,某结点在第
i
层,则其孩子结点在第i+1
层。上图中,A
在第一层,B、C、D
在第二层,E、F、G
在第三层。 - 树的高度。一棵树的最大层数记为树的高度或深度。上图树高为3。
- 有序(无序)树。若将树种结点的各子树看成是从左到右具有次序的,即不能交换,则称该树为有序树,否则称为无序树。
3.二叉树的定义
二叉树是n(n>=0)
个结点的有限集合,它或者是空树(n=0)
,或者是由一个根节点及两棵不相交的且分别称为左、右子树的二叉树所组成。
二叉树同样具有递归性质。
树和二叉树是两个不同的概念,它们之间最主要的区别是:
- 二叉树中结点的子树要区分左子树和右子树,即时在结点只有一棵树的情况下,也要明确指出该子树是左子树还是右子树;
- 二叉树结点最大度为
2
,而树中不限制结点的度数。
二叉树结构如下图所示:
二叉树与普通树的区别如下图所示:
(二)二叉树的性质与存储结构
1.二叉树的性质
- 二叉树第
i
层(i>=1)
上最多有2^(i-1)
个节点; - 高度为k的二叉树最多有
2^k-1
个节点(k>=1)
; - 对于任何一棵二叉树,若其终端结点数为
n₀
,度为2
的结点数位n₂
,则n₀=n₂+1
; - 具有
n
个结点的完全二叉树的深度为[㏒₂n]+1
若深度为k
的二叉树有2^k-1
个结点,则称其为满二叉树。
对二叉树的结点进行连续编号:约定编号从根结点起,自上而下、自左至右依次进行。
深度为k
,有n
个结点的二叉树,当且仅当其每个结点都与深度为k
的满二叉树中编号从1
至n
的结点一一对应时,称之为完全二叉树。
满二叉树、完全二叉树、非完全二叉树如下图所示:
2.二叉树的存储结构
(1)二叉树的顺序存储结构
顺序存储是用一组地址连续的存储单元存储二叉树中的结点,必须把结点排成一个适当的线性序列,并且结点在这个序列中的相互位置能反映出结点之间的逻辑关系。
对于深度为k
的完全二叉树,除第k
层外,其余各层中含有最大的结点数,及每一层的结点数恰为其上一层结点数的两倍,由此从一个结点的编号可推知其双亲、左孩子和右孩子的编号。
二叉树的顺序存储结构:
(2)二叉树的链式存储结构
由于二叉树的结点中包含有数据元素、左子树的根、右子树的根及双亲等信息,因此可以用三叉链表或二叉链表来存储二叉树,链表的头指针指向二叉树的根节点。
二叉树的链表存储结构如下图所示:
(三)二叉树的遍历
遍历是按照某种策略访问树中的每个结点,且仅访问一次的过程。
按照先遍历左子树后遍历右子树的约定,根据访问根结点位置的不同,可得到二叉树的先序、中序、后序三种遍历方法。
- 先序:根左右
- 中序:左根右
- 后序:左右根
不论按照哪种次序遍历,对于含有n
个结点的二叉树,遍历算法的时间复杂度都为O(n)
;二叉树是有n
个结点且高度为n
的单枝树,遍历算法的空间复杂度也为O(n)
。
遍历二叉树的过程实质上是按照一定的规则将树中的结点排成一个线性序列的过程,因此遍历操作得到的是树中结点的一个线性序列。
从树的根节点出发,首先访问第一层的树根结点,然后从左到右依次访问第二层上的结点,其次是第三层上的结点,依此类推,自上而下、自左至右逐层访问树中各结点的过程就是层序遍历。
(四)线索二叉树
1.线索二叉树的定义
用线索二叉树保存在遍历的动态过程中获得的某结点在任一遍历序列中的前驱和后继。
2.建立线索二叉树
为了保存结点在任一序列中的前驱和后继信息,可以在每个结点中增加两个指针域来存放遍历时得到的前驱和后继信息。
若二叉树采用二叉链表做存储结构,则需要在结点中增加标志ltag
和rtag
,以此来区分孩子指针的指向。如下图所示:
采用以上结构的链表称为线索链表,其中指向结点前驱、后继的指针称为线索。加上线索的二叉树称为线索二叉树。对二叉树以某种次序遍历使其成为线索二叉树的过程称为线索化。
3.访问线索二叉树
在线索二叉树中查找结点的前驱和后继的方法。
以中序线索二叉树为例,令p
指向树中的某个结点,查找p
所指结点的后继结点的方法如下所述:
- 若
p->rtag==1
,则p->rchild
即指向其后继节点; - 若
p->rtag==0
,则p
所指结点的中序后继必然是其右子树中进行中序遍历得到的第一个结点。
(五)最优二叉树
1.最优二叉树
又称为哈夫曼树,是一类带权路径长度最短的树。
路径是从树中一个结点到另一个结点之间的通路,路径上的分支数目称为路径长度。
树的路径长度是从树根到每一个叶子之间的路径长度之和。记为WPL
,公式为:
其中,n
为带权叶子结点数目,wk
为叶子结点的权值,lk
为叶子结点到根的路径长度。
结点的带权路径长度为从该结点到树根之间的路径长度与该结点权值的乘积。
哈夫曼树是指权值为w1,w2,...,wn
的n
个叶子结点的二叉树中带权路径长度最小的二叉树。
构造最优二叉树的方法:
- (1)根据给定的
n
个权值{w1,w2,...,wn}
,构成n
棵二叉树的集合F={T1,T2,...,Tn}
,其中,每棵树Ti
中只有一个带权为wi
的根结点,其左、右子树均为空; - (2)在
F
中选取两棵权值最小的树作为左、右子树构造一棵新的二叉树,置新构造二叉树的根节点的权值为其左、右子树根结点的权值之和; - (3)从
F
中删除这两棵树,同时将新得到的二叉树加入到F
中; - 重复(2)、(3)步,直到
F
中只含有一棵树为止,这棵树便是最优二叉树(哈夫曼树)。
2.哈夫曼编码
对每个字符编制相同长度的二进制码,则称为等长编码。
利用哈夫曼树译码的过程为:从根节点出发,按二进制位串中的0
和1
确定是进入左分支还是右分支,当到达叶子结点时译出一个字符;若位串未结束,则回到根结点继续上述译码过程,直到位串结束。
(六)树和森林
1.树的存储结构
常用的树存储有双亲表示法、孩子表示法和孩子兄弟表示法。
(1)树的双亲表示法
用一组地址连续的单元存储树的结点,并在每个结点中附设一个指示器,指出其双亲结点在该存储结构中的位置。
树的双亲表示发如下图所示:
(2)树的孩子表示法
在存储结构中用指针指示出结点的每个孩子,为树中每个结点的孩子建立一个链表,即每个结点的所有孩子结点构成一个用单链表表示的线性表,则n
个结点的树具有n
个单链表。将这n
个单链表的头指针又排成一个线性表。
树的孩子表示法如下图所示:
(3)孩子兄弟表示法
又称为二叉链表表示法,在链表的结点中设置两个指针域分别指向该结点的第一个孩子和下一个兄弟。
2.树和森林的遍历
(1)树的遍历
- 先根遍历,先访问树的根节点,然后依次先根遍历根的各棵子树。等同于对转换所得的二叉树进行先序遍历。
- 后根遍历,先依次后根遍历树根的各棵子树,然后访问树根结点。等同于对转换所得的二叉树进行中序遍历。
(2)森林的遍历
- 先序遍历森林,先访问森林中第一棵树的根节点,再先序遍历第一棵树根节点的子树森林,最后先序遍历除第一棵树之外剩余的树所构成的森林。
- 中序遍历森林,先中序遍历森林中第一棵树的子树森林,然后访问第一棵树的根节点,最后中序遍历除第一棵树之外剩余的树所构成的森林。
3.树、森林和二叉树之间的相互转换
任何一个森林或一棵树可以对应表示为一棵二叉树,而任何一棵二叉树也能对应到一个森林或一棵树上。
(1)树、森林转换为二叉树
利用树的孩子兄弟表示法可导出树与二叉树的对应关系,在树的孩子兄弟表示法中,从物理结构上看与二叉树的二叉链表表示法相同,因此就可以利用这种同一存储结构的不同解释将一棵树转换为一棵二叉树。
树转换为二叉树如下图所示:
森林转为二叉树如下图所示:
(2)二叉树转换为树和森林
二叉树转为树如下图所示:
网友评论