数据结构之树和二叉树
第七章树和二叉树
第一节树的概念
1.概念
 是n(n≥0)个节点的有限集。当n=0时,称为空树。在任意一棵非空树中应满足:
- 有且仅有一个特定的称为根的结点;
 - 当n>1时,其余结点可分为m(m>0)个互不相交的有限集,其中每个集合本身又是一棵树,并且成为根的子树
 
2.特点
- 树的根结点没有前驱,除根节点外的所有结点有且只有一个前驱;
 - 树中所有结点可以由零个或多个后继
 
3.基本性质
\begin{flalign}
&1)树中的结点数等于所有结点的度数之和+1&&\
&2)度为m的树中第i层上至多有m^{i-1}个结点(i≥1)\
&3)高度为h的m叉树至多有(m^h-1)/(m-1)个结点\
&4)n结点m叉树最小高度为\lceil log_m[n(m-1)+1] \rceil \
\end{flalign}
4.存储结构
(1)双亲表示法
graph TB; R((R)) A((A)) B((B)) C((C)) D((D)) E((E)) F((F)) G((G)) H((H)) K((K)) R-->A R-->B R-->C A-->D A-->E C-->F F-->G F-->H F-->K
| data | parent | |
|---|---|---|
| 0 | R | -1 | 
| 1 | A | 0 | 
| 2 | B | 0 | 
| 3 | C | 0 | 
| 4 | D | 1 | 
| 5 | E | 1 | 
| 6 | F | 3 | 
| 7 | G | 6 | 
| 8 | H | 6 | 
| 9 | K | 6 | 
(2)孩子表示法
将每个节点的孩子结点都用单链表链接起来形成一个线性结构,此时n个结点就有n个孩子链表(叶子结点链表为空表);
这种存储方式寻找子女的操作非常直接,而寻找双亲的操作需要遍历n个结点中孩子链表指针域所指向的n个孩子链表。
(3)孩子兄弟表示法
优点:方便地实现树转换为二叉树的操作,易于查找结点的孩子等;
缺点:从当前结点查找其双亲结点比较麻烦
①在兄弟结点之间加一条线;
②对每个结点,只保留它与i一个孩子的连线,而与其他孩子 连线全部抹掉;
③以树根为轴心,顺时针旋转45°。
5.树、森林与二叉树遍历的对应关系
| 树 | 森林 | 二叉树 | 
|---|---|---|
| 先根遍历 | 先序遍历 | 先序遍历 | 
| 后根遍历 | 中序遍历 | 中序遍历 | 
第二节二叉树
1.概念和性质
(1)概念
 一棵二叉树是结点的一个有限集合,该集合:
-  或者为空;
 -  由一个根节点加上两棵别称为左子树和右子树的二叉树组成
 
满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
完全二叉树:效率很高的数据结构,由满二叉树而引出来的。是一种特殊的完全二叉树。
二叉排序树:左<中<右.
平衡二叉树:左子树与右子树深度之差不超过1。
(2)性质
\begin{flalign}
&1)n_0 = n_2 +1\
&2)非空二叉树上第k层至多有2^{k-1}个结点(k≥1)\
&3)高度为h的二叉树至少有2^h-1个结点(h≥1)\
&4)对完全二叉树按向上到下、从左到右的顺序依次编号1,2,…,n,则有以下关系:\
&~①当i>1时,结点i的双亲的编号是\lfloor i/2 \rfloor,即当i为偶数时,其双亲的编号是i/2,它是双亲的左孩子。当i为奇数时,其双亲的编号是(i-1)/2,它是双亲的右孩子。\
&~②当2i≤n时,结点i的左孩子编号为2i,否则无左孩子。\
&~③当2i+1≤n时,结点i的右孩子编号为2i+1,否则无右孩子。\
&~④结点i所在层次(深度)为\lfloor log_2i \rfloor+1。\
&5)具有n个(n>0)结点的完全二叉树的高度为\lceil log_2(n+1) \rceil 或\lfloor log_2n \rfloor +1。
\end{flalign}
2.存储结构和基本算法
(1)顺序存储结构
(2)链式存储结构
| lchild | data | rchild | 
|---|
1  | typedef struct BiTree{  | 
第三节二叉树的遍历算法
1.先序遍历
递归算法
1  | void PreOrder(BiTree T){  | 
非递归算法
1  | void PreOrder(BiTree T){  | 
2.中序遍历
递归算法
1  | void InOrder(BiTree T){  | 
非递归算法
1  | void InOrder(BiTree T){  | 
3.后序遍历
递归算法
1  | void PostOrder(BiTree T){  | 
非递归算法
1  | void PostOrder(BiTree T){  | 
4.层次遍历
1  | void LevelOrder(BiTree T){  | 
第四节线索二叉树
是以一定的规则将二叉树中的结点排列成一个线性序列,从而得到集中遍历序列,使得该序列中的每个结点(第一个和最后一个结点除外)都有一个直接前去和直接后继。
目的:为了加快查找结点前驱和后继的速度。
空指针 = 线索数 = n+1
| lchild | ltag | data | rtag | rchild | 
|---|
ltag
-  0 lchild域指示结点的左孩子
 -  1 lchild域指示结点的前驱
 
rtag
-  0 rchild域指示结点的右孩子
 -  1 rchild域指示结点的前驱
 
存储结构
1  | typedef struct ThreadNode{  | 
第五节哈夫曼树
1.概念
树中所有叶结点的带权路径长度之和称为该树的带权路径长度,记作:
$$
WPL = \sum_{i=1}^nw_il_i
$$
举例如下哈夫曼树,WPL = (4+2)3+52+7*1 = 35
graph TB; A((A)) B((B)) C((C)) D((D:7)) E((E:5)) F((F:2)) G((G:4)) A-->D A-->B B-->C B-->E C-->G C-->F
2.编码问题(左0右1)
graph TB; A((A)) B((B)) C((C)) D((D:7)) E((E:5)) F((F:2)) G((G:4)) A--1-->D A--0-->B B--0-->C B--1-->E C--0-->G C--1-->F
| D | E | F | G | 
|---|---|---|---|
| 1 | 01 | 001 | 000 |