数据结构:赫夫曼树的编码和译码过程
- 写在前面的话
这篇文章是根据严蔚敏版的数据结构中6.6.2赫夫曼编码中的部分代码所写,主要是记录一下自己对这些代码的理解,并且在那本书中采用了类c语言写的,在计算机上无法直接实现,我便根据自己的理解对代码进行适当的改写,使其在计算机上可以运行。
(此外,吐槽一句,书上用所谓的类c语言写,确实节省了书的空间,老师讲的时候也更方便,但是自己去实现的时候是真的令人头秃。。。。。)
- 学前小知识
路径长度:从树的一个结点到另一个结点之间的分支构成这两个节点之间的路径,而路径上的分支数目便称作路径长度。从树根到每一个结点的路径长度之和称为树的路径长度。
树的带全路径长度:结点的带全路径长度为该从结点到树根之间的路径长度与结点上的权的乘积,而树中所有叶子结点的带全路径长度之和叫做熟的带全路径长度。
赫夫曼树:又称最优二叉树,是指带全路径长度WPL最小的二叉树。
前缀编码:若要设计长短不等的编码,则必须是任一个字符的编码都不是另一个字符编码的前缀。而赫夫曼编码便是总长度最短的前缀编码。
- 赫夫曼树的编码
当给到我们一组有权重的数时:
weight | parent | lchild | rchild | |
---|---|---|---|---|
1 | 5 | 0 | 0 | 0 |
2 | 29 | 0 | 0 | 0 |
3 | 7 | 0 | 0 | 0 |
4 | 8 | 0 | 0 | 0 |
5 | 14 | 0 | 0 | 0 |
6 | 23 | 0 | 0 | 0 |
7 | 3 | 0 | 0 | 0 |
8 | 11 | 0 | 0 | 0 |
9 | - | 0 | 0 | 0 |
10 | - | 0 | 0 | 0 |
11 | - | 0 | 0 | 0 |
12 | - | 0 | 0 | 0 |
13 | - | 0 | 0 | 0 |
14 | - | 0 | 0 | 0 |
15 | - | 0 | 0 | 0 |
( a)HT的初态
首先便是将其构成赫夫曼树。其方法如图所示:
由方法可将上面的数组填充完整:
weight | parent | lchild | rchild | |
---|---|---|---|---|
1 | 5 | 9 | 0 | 0 |
2 | 29 | 14 | 0 | 0 |
3 | 7 | 10 | 0 | 0 |
4 | 8 | 10 | 0 | 0 |
5 | 14 | 12 | 0 | 0 |
6 | 23 | 13 | 0 | 0 |
7 | 3 | 9 | 0 | 0 |
8 | 11 | 11 | 0 | 0 |
9 | 8 | 11 | 1 | 7 |
10 | 15 | 12 | 3 | 4 |
11 | 19 | 13 | 8 | 9 |
12 | 29 | 14 | 5 | 10 |
13 | 42 | 15 | 6 | 11 |
14 | 58 | 15 | 2 | 12 |
15 | 100 | 0 | 13 | 14 |
(b)HT的终态
由定义可知,赫夫曼树中没有度为1的结点,则一棵有n个子叶结点的赫夫曼树共有2n-1个结点。
而根据图6.25可知若要求赫夫曼编码,则需从叶子结点出发走出一条从叶子到根的路径。所以在定义赫夫曼树和赫夫曼编码的存储结构时,不仅要考虑一个结点的权重,还需考虑该结点的双亲和孩子结点的位置。
所以其顺序存储结构可以这样定义
typedef struct