《算法设计与分析》上机实验报告(3)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
福州大学数学与计算机科学学院《算法设计与分析》上机实验报告(3)
求任一字符的代码都不是其他字符代码的前缀。这种编码称为前缀码。编码的前缀性质可以使译码方法非常简单;例如001011101可以唯一的分解为0,0,101,1101,因而其译码为aabe。
哈夫曼提出了构造最优前缀码的贪心算法,由此产生的编码方案称为哈夫曼算法。
2.算法的设计思想
哈夫曼编码依据贪心算法来构造最优前缀码,构造思想步骤如下:
(1)哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树T。
(2)算法以|C|个叶结点开始,执行|C|-1次的“合并”运算后产生最终所要求的树T。
(3)假设编码字符集中每一字符c的频率是f(c)。以f为键值的优先队列Q用在贪心选择时有效地确定算法当前要合并的2棵具有最小频率的树。一旦2棵具有最小频率的树合并后,产生一棵新的树,其频率为合并的2棵树的频率之和,并将新树插入优先队列Q。经过n-1次的合并后,优先队列中只剩下一棵树,即所要求的树T。
构造过程如图所示:
3.算法正确性证明
由此可知,树T和T'的前缀码的平均码长之差为:
码长,同时,仅最优一位编码不同。
(2)最优子结构性质
二叉树T表示字符集C的一个最优前缀码,x和y是树T 中的两个叶子且为兄弟,z是它们的父亲。若将z当作是具有频率f(z)=f(x)+f(y)的字符,则树T’=T-{x,y}表示字符集C’=C-{x, y} ∪ { z}的一个最优前缀码。因此,有:
如果T’不是C’的最优前缀码,假定T”是C’的最优前缀码,那么有
,显然T”’是比T更优的前缀码,跟前提矛盾!故T'所表示的C'的前缀码是最优的。
由贪心选择性质和最优子结构性质可以推出哈夫曼算法是正确的,即HuffmanTree产生的一棵最优前缀编码树。
4.哈夫曼编码算法的程序代码
(1)huffman.cpp,程序主文件
1.//huffman 贪心算法哈夫曼算法
2.#include "stdafx.h"
3.#include "BinaryTree.h"
4.#include "MinHeap.h"
5.#include
ing namespace std;
7.
8.const int N = 6;
9.
10.template
11.
12.template
13.BinaryTree
;
14.
15.template
16.class Huffman
17.{
18.friend BinaryTree
[],int);
19.public:
20. operator Type() const
21. {
22.return weight;
23. }
24.//private:
25. BinaryTree
26. Type weight;
27.};
28.
29.int main()
30.{
31.char c[] = {'0','a','b','c','d','e','f'
};
32.int f[] = {0,45,13,12,16,9,5};//下标从1
开始
33. BinaryTree
34.
35. cout<<"各字符出现的对应频率分别为:
"< 36.for(int i=1; i<=N; i++) 37. { 38. cout< 39. } 40. cout< 41. 42. cout<<"生成二叉树的前序遍历结果为: "< 43. t.Pre_Order(); 44. cout< 45. 46. cout<<"生成二叉树的中序遍历结果为: "< 47. t.In_Order(); 48. cout< 49. 50. t.DestroyTree(); 51.return 0; 52.} 53. 54.template 55.BinaryTree 56.{ 57.//生成单节点树 58. Huffman 1]; 59. BinaryTree 60. 61.for(int i=1; i<=n; i++) 62. { 63. z.MakeTree(i,zero,zero); 64. w[i].weight = f[i]; 65. w[i].tree = z; 66. } 67. 68.//建优先队列 69. MinHeap 70.for(int i=1; i<=n; i++) Q.Insert(w[i]);