内容正文:
第六章 树和二叉树
6.1 树的定义
6.2 二叉树
6.3 遍历二叉树和线索二叉树
6.4 树的存储结构
6.5 哈夫曼树
树和森林的遍历
树的遍历
遍历——按一定规律走遍树的各个顶点,且使每一顶点仅被访问一次,即找一个完整而有规律的走法,以得到树中所有结点的一个线性排列
常用方法
先根(序)遍历:先访问树的根结点,然后依次先根遍历根的每棵子树
后根(序)遍历:先依次后根遍历每棵子树,然后访问根结点
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
先序遍历:
后序遍历:
A
B
E
F
I
G
C
D
H
J
K
L
N
O
M
E
I
F
G
B
C
J
K
N
O
L
M
H
D
A
讨论:若采用“先转换,后遍历”方式,结果是否一样?
a
b
d
e
c
先序遍历:
后序遍历:
中序遍历:
d e c b a
a
b
d
e
c
a b c d e
b d c e a
1. 树的先序遍历二法相同;
2. 树的后序遍历相当于对应二叉树的中序遍历;
3. 树没有中序遍历,因为子树无左右之分。
结论:
先序遍历
若森林为空,返回;
访问森林中第一棵树的根结点;
先序遍历第一棵树中根结点的子树森林;
先序遍历除去第一棵树之后剩余的树构成的森林。
后序遍历
若森林为空,返回;
后序遍历森林中第一棵树的根结点的子树森林;
访问第一棵树的根结点;
后序遍历除去第一棵树之后剩余的树构成的森林。
森林的遍历
A
B
C
D
E
F
G
H
J
I
讨论:若采用“先转换,后遍历”方式,结果是否相同?
例如:
A
B
C
D
E
F
G
H
J
I
先序序列:
后序序列:
A B C D E F G H I J
B C D A F E H J I G
A
B
C
D
E
F
G
H
J
I
先序序列:
中序序列:
A B C D E F G H I J
B C D A F E H J I G
结论:森林的先序和中序遍历等同于对应的二叉树的先序和后序遍历。
一、基本术语
1.路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或子孙结点之间的通路,称为路径。通路中分支的数目称为路径长度。
若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2.结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
6.5 哈夫曼树
3.树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为wpl= ,
其中n 为叶子结点数目,wi为第i 个叶子结点的权值,li 为第i 个叶子结点的路径长度。
二、构造哈夫曼树
1.哈夫曼树的定义
在一棵二叉树中,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。
例如: 有4个结点,权值分别为7,5,2,4,构造有4个叶子结点的二叉树
a
b
c
d
7
5
2
4
WPL=7*2+5*2+2*2+4*2=36
d
c
a
b
2
4
7
5
WPL=7*3+5*3+2*1+4*2=46
a
b
c
d
7
5
2
4
WPL=7*1+5*2+2*3+4*3=35
2.哈夫曼树的构造
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1,w2,…,wn,则哈夫曼树的构造规则为:
(1) 将w1,w2,…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为我们所求得的哈夫曼树。
下面给出哈夫曼树的构造过程,假设给定的叶子结点的权分别为1,5,7,3,则构造哈夫曼树过程如图所示。
从图7-24可知,n 个权值构造哈夫曼树需n-1次合并,每次合并,森林中的树数目减1,最后森林中只剩下一棵树,即为我们求得的哈夫曼树。
3、哈夫曼树构造程序
一棵有n个叶子结点的Huffman树有2n-1个结点。采用顺序存储结构——一维结构数组存储结点信息。结点类型定义为:
typedef struct
{ int weight;
int parent,lchild,rchild;
}JD;
#define MAX 100
void huffman(int n,int w[],JD t[])
{ int i,j,k,x1,x2,m1,m2;
for(i=1;i<(2*n);i++)
{ t[i].parent=t