赫夫曼树及其编码
- 格式:ppt
- 大小:903.00 KB
- 文档页数:29
最优⼆叉树(哈夫曼树)的构建及编码参考:数据结构教程(第五版)李春葆主编⼀,概述1,概念 结点的带权路径长度: 从根节点到该结点之间的路径长度与该结点上权的乘积。
树的带权路径长度: 树中所有叶结点的带权路径长度之和。
2,哈夫曼树(Huffman Tree) 给定 n 个权值作为 n 个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,则称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
⼆,哈夫曼树的构建1,思考 要实现哈夫曼树⾸先有个问题摆在眼前,那就是哈夫曼树⽤什么数据结构表⽰? ⾸先,我们想到的肯定数组了,因为数组是最简单和⽅便的。
⽤数组表⽰⼆叉树有两种⽅法: 第⼀种适⽤于所有的树。
即利⽤树的每个结点最多只有⼀个⽗节点这种特性,⽤ p[ i ] 表⽰ i 结点的根节点,进⽽表⽰树的⽅法。
但这种⽅法是有缺陷的,权重的值需要另设⼀个数组表⽰;每次找⼦节点都要遍历⼀遍数组,⼗分浪费时间。
第⼆种只适⽤于⼆叉树。
即利⽤⼆叉树每个结点最多只有两个⼦节点的特点。
从下标 0 开始表⽰根节点,编号为 i 结点即为 2 * i + 1 和 2 * i + 2,⽗节点为 ( i - 1) / 2,没有⽤到的空间⽤ -1 表⽰。
但这种⽅法也有问题,即哈夫曼树是从叶结点⾃下往上构建的,⼀开始树叶的位置会因为⽆法确定⾃⾝的深度⽽⽆法确定,从⽽⽆法构造。
既然如此,只能⽤⽐较⿇烦的结构体数组表⽰⼆叉树了。
typedef struct HTNode // 哈夫曼树结点{double w; // 权重int p, lc, rc;}htn;2,算法思想 感觉⽐较偏向于贪⼼,权重最⼩的叶⼦节点要离根节点越远,⼜因为我们是从叶⼦结点开始构造最优树的,所以肯定是从最远的结点开始构造,即权重最⼩的结点开始构造。
所以先选择权重最⼩的两个结点,构造⼀棵⼩⼆叉树。
然后那两个最⼩权值的结点因为已经构造完了,不会在⽤了,就不去考虑它了,将新⽣成的根节点作为新的叶⼦节加⼊剩下的叶⼦节点,⼜因为该根节点要能代表整个以它为根节点的⼆叉树的权重,所以其权值要为其所有⼦节点的权重之和。
c语言哈夫曼树的构造及编码一、哈夫曼树概述哈夫曼树是一种特殊的二叉树,它的构建基于贪心算法。
它的主要应用是在数据压缩和编码中,可以将频率高的字符用较短的编码表示,从而减小数据存储和传输时所需的空间和时间。
二、哈夫曼树的构造1. 哈夫曼树的定义哈夫曼树是一棵带权路径长度最短的二叉树。
带权路径长度是指所有叶子节点到根节点之间路径长度与其权值乘积之和。
2. 构造步骤(1) 将待编码字符按照出现频率从小到大排序。
(2) 取出两个权值最小的节点作为左右子节点,构建一棵新的二叉树。
(3) 将新构建的二叉树加入到原来排序后队列中。
(4) 重复上述步骤,直到队列只剩下一个节点,该节点即为哈夫曼树的根节点。
3. C语言代码实现以下代码实现了一个简单版哈夫曼树构造函数:```ctypedef struct TreeNode {int weight; // 权重值struct TreeNode *leftChild; // 左子节点指针struct TreeNode *rightChild; // 右子节点指针} TreeNode;// 构造哈夫曼树函数TreeNode* createHuffmanTree(int* weights, int n) {// 根据权值数组构建节点队列,每个节点都是一棵单独的二叉树TreeNode** nodes = (TreeNode**)malloc(sizeof(TreeNode*) * n);for (int i = 0; i < n; i++) {nodes[i] = (TreeNode*)malloc(sizeof(TreeNode));nodes[i]->weight = weights[i];nodes[i]->leftChild = NULL;nodes[i]->rightChild = NULL;}// 构建哈夫曼树while (n > 1) {int minIndex1 = -1, minIndex2 = -1;for (int i = 0; i < n; i++) {if (nodes[i] != NULL) {if (minIndex1 == -1 || nodes[i]->weight < nodes[minIndex1]->weight) {minIndex2 = minIndex1;minIndex1 = i;} else if (minIndex2 == -1 || nodes[i]->weight < nodes[minIndex2]->weight) {minIndex2 = i;}}}TreeNode* newNode =(TreeNode*)malloc(sizeof(TreeNode));newNode->weight = nodes[minIndex1]->weight + nodes[minIndex2]->weight;newNode->leftChild = nodes[minIndex1];newNode->rightChild = nodes[minIndex2];// 将新构建的二叉树加入到原来排序后队列中nodes[minIndex1] = newNode;nodes[minIndex2] = NULL;n--;}return nodes[minIndex1];}```三、哈夫曼编码1. 哈夫曼编码的定义哈夫曼编码是一种前缀编码方式,它将每个字符的编码表示为二进制串。
哈夫曼树及哈夫曼编码的算法实现c语言1.引言1.1 概述哈夫曼树及哈夫曼编码是数据压缩和编码中常用的重要算法。
哈夫曼树由大卫·哈夫曼于1952年提出,用于根据字符出现的频率构建一种最优的前缀编码方式。
而哈夫曼编码则是根据哈夫曼树构建的编码表将字符进行编码的过程。
在现代通信和计算机领域,数据传输和存储中往往需要大量的空间。
为了有效利用有限的资源,减少数据的存储和传输成本,数据压缩成为一个重要的技术。
而哈夫曼树及哈夫曼编码正是数据压缩中常用的技术之一。
哈夫曼树的概念及原理是基于字符的频率和概率进行构建的。
在哈夫曼树中,字符出现频率越高的节点越接近根节点,出现频率越低的节点离根节点越远。
这种构建方式保证了哈夫曼树的最优性,即最小化编码的总长度。
哈夫曼编码的算法实现是根据哈夫曼树构建的编码表进行的。
编码表中,每个字符都与一段二进制编码相对应。
在进行数据压缩和解压缩时,通过查表的方式将字符转化为相应的二进制编码,或将二进制编码解析为原始字符。
本文旨在介绍哈夫曼树及哈夫曼编码的概念和原理,并通过C语言实现算法。
通过深入理解哈夫曼树及哈夫曼编码的实现过程,可以更好地理解数据压缩和编码的原理,为后续的研究和应用提供基础。
接下来,我们将首先介绍哈夫曼树的概念和原理,然后详细讲解哈夫曼编码的算法实现。
最后,我们将总结哈夫曼树及哈夫曼编码的重要性,并提出对哈夫曼树和哈夫曼编码进一步研究的方向。
让我们一起深入探索哈夫曼树及哈夫曼编码的奥秘吧!1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分主要介绍了本文的组织结构和各个章节的内容概述,以帮助读者更好地理解全文的逻辑结构和内容安排。
首先,本文包括引言、正文和结论三个部分。
引言部分主要对哈夫曼树及哈夫曼编码的算法实现进行了概述,包括相关的概念、原理和目的。
正文部分则深入介绍了哈夫曼树的概念和原理,以及哈夫曼编码的算法实现。
最后,结论部分对本文的主要内容进行了总结,并提出了对哈夫曼树和哈夫曼编码的进一步研究方向。
哈夫曼(huffman)树和哈夫曼编码讨论QQ群:待定哈夫曼树哈夫曼树也叫最优二叉树(哈夫曼树)问题:什么是哈夫曼树?例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。
if (a < 60){b = 'E';}else if (a < 70) {b = ‘D’;}else if (a<80) {b = ‘C’;}else if (a<90){b = ‘B’;}else {b = ‘A’;}判别树:用于描述分类过程的二叉树。
如果每次输入量都很大,那么应该考虑程序运行的时间如果学生的总成绩数据有10000条,则5%的数据需1 次比较,15%的数据需 2 次比较,40%的数据需 3 次比较,40%的数据需 4 次比较,因此 10000 个数据比较的次数为: 10000 (5%+2×15%+3×40%+4×40%)=31500次此种形状的二叉树,需要的比较次数是:10000 (3×20%+2×80%)=22000次,显然:两种判别树的效率是不一样的。
问题:能不能找到一种效率最高的判别树呢?那就是哈夫曼树回忆树的基本概念和术语路径:若树中存在一个结点序列k1,k2,…,kj,使得ki是ki+1的双亲,则称该结点序列是从k1到kj的一条路径。
路径长度:等于路径上的结点数减1。
结点的权:在许多应用中,常常将树中的结点赋予一个有意义的数,称为该结点的权。
结点的带权路径长度:是指该结点到树根之间的路径长度与该结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记作:其中,n表示叶子结点的数目,wi和li分别表示叶子结点ki的权值和树根结点到叶子结点ki之间的路径长度。
赫夫曼树(哈夫曼树,huffman树)定义:在权为w1,w2,…,wn的n个叶子结点的所有二叉树中,带权路径长度WPL最小的二叉树称为赫夫曼树或最优二叉树。
数据结构(⼆⼗七)Huffman树和Huffman编码 Huffman树是⼀种在编码技术⽅⾯得到⼴泛应⽤的⼆叉树,它也是⼀种最优⼆叉树。
⼀、霍夫曼树的基本概念 1.结点的路径和结点的路径长度:结点间的路径是指从⼀个结点到另⼀个结点所经历的结点和分⽀序列。
结点的路径长度是指从根结点到该结点间的路径上的分⽀数⽬。
2.结点的权和结点的带权路径长度:结点的权是指结点被赋予⼀个具有某种实际意义的数值。
结点的带权路径长度是该结点的路径长度与结点的权值的乘积。
3.树的长度和树的带权路径长度:树的长度就是从根结点到每⼀结点的路径长度之和。
树的带权路径长度就是所有叶结点的带权路径长度之和。
4.最优⼆叉树:带权路径长度WPL最⼩的⼆叉树称为霍夫曼树(Huffman Tree)或最优⼆叉树。
⼆叉树a的WPL = 5 x 1 + 15 x 2 + 40 x 3 + 30 x 4 + 10 x 5 = 315 ⼆叉树b的WPL = 5 x 3 + 15 x 3 + 40 x 2 + 30 x 2 + 10 x 2 = 220 ⼆、霍夫曼树的构造⽅法由给定的n个权值{w1,w2,... ,wn}构成由n棵⼆叉树所构成的森林F={T1,T2,...,Tn},其中每棵⼆叉树只有⼀个根结点,并且根结点的权值对应于w1,w2,...,wn在F中选取根结点的权值最⼩的两棵树,分别把它们作为左⼦树和右⼦树去构造⼀棵新的⼆叉树,新的⼆叉树的各结点的权值为左、右⼦树的权值之和在F中删除上⼀步中选中的两棵树,并把新产⽣的⼆叉树加⼊到F中重复第2步和第3步,直到F只含⼀棵树为⽌,这棵树就是霍夫曼树。
三、霍夫曼编码 霍夫曼树更⼤的⽬的是解决了当年远距离通信(电报)的数据传输的最优化问题。
霍夫曼编码的定义:设需要编码的字符集为(d1,d2,...,dn)各个字符在电⽂中出现的次数或者频率集合为{w1,w2,...,wn},以d1,d2,...,dn为叶⼦结点,w1,w2,...,wn作为相应叶⼦结点的权值来构造⼀棵霍夫曼树。
数据结构c+python代码6:哈夫曼树构造及编码⾸先介绍⼀下什么是哈夫曼树?给定N个权值作为N个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树(Huffman Tree)。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
哈夫曼树⼜称为最优树.1、路径和路径长度在⼀棵树中,从⼀个结点往下可以达到的孩⼦或孙⼦结点之间的通路,称为路径。
通路中分⽀的数⽬称为路径长度。
若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度哈夫曼树哈夫曼树(3张)若将树中结点赋给⼀个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度树的带权路径长度规定为所有叶⼦结点的带权路径长度之和,记为WPL。
哈夫曼树的构造假设有n个权值,则构造出的哈夫曼树有n个叶⼦结点。
n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有⼀个结点);(2) 在森林中选出两个根结点的权值最⼩的树合并,作为⼀棵新树的左、右⼦树,且新树的根结点权值为其左、右⼦树根结点权值之和;(3)从森林中删除选取的两棵树,并将新树加⼊森林;(4)重复(2)、(3)步,直到森林中只剩⼀棵树为⽌,该树即为所求得的哈夫曼树。
c代码过程分析构造哈夫曼树算法的实现可以分成两⼤部分:1、初始化:⾸先动态申请2n个单元;然后循环2n-1次,从1号单元开始,依次将1⾄2n-1所有单元中的双亲、左孩⼦、右孩⼦的下标都初始化为0;最后再循环n次,输⼊前n个单元中叶⼦节点的权值。
2、创建树:循环n-1次,通过n-1次的选择、删除与合并来创建哈夫曼树。
选择是从当前森林中选择双亲为0且权值最⼩的两个树跟节点是s1和s2;删除是指将节点s1和s2的双亲改为⾮0;合并就是将s1和s2的权值和作为⼀个新节点的权值依次存⼊到数组的第n+1之后的单元中,同时记录这个新节点左孩⼦的下标为s1,右孩⼦的下标为s2。
一、目的和要求1、通过本实验,熟悉二叉树、Huffman树的基本概念,掌握二叉树的存储结构及各种算法;2、熟悉用Huffman树进行电文的加密与解密算法。
二、实验内容1、Huffman树的存储方式;2、加密与解密算法在电文编码中的应用。
三、实验原理给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。
Huffman树是一种特殊的二叉树,其叶结点的编码是一种前缀码,同时,通过统计字符的频度,能够达到编码电文的最小化。
哈夫曼树的构造假设有n个权值,则构造出的哈夫曼树有n个叶子结点。
n个权值分别设为w1、w2、…、wn,则哈夫曼树的构造规则为:(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;(3)从森林中删除选取的两棵树,并将新树加入森林;(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
四、实验步骤1、统计电文中字符的出现频率;2. 用统计频率建立Hffman树;3.生成前缀码;4.建立huffman树的解码算法;5.用随机输入的电文完成编码与解码过程。
五、程序源代码及注释#include<stdio.h>#include<malloc.h>#include<string.h>#include<stdio.h>#include<string.h>#include<malloc.h>typedef struct{int weight;unsigned int parent,lchild,rchild;char c;}Haffman;typedef struct {char a;int n;}cc;void input(char c[100],cc c1[100],int *n){int i,j,t,k,flag=0;i=strlen(c);c1[0].n=1;*n=1;c1[0].a=c[0];for(j=1;j<i;j++){for(t=0;t<*n;t++)if(c1[t].a==c[j]){flag=1;c1[t].n=c1[t].n+1;}if(flag!=1){c1[*n].n=1;c1[*n].a=c[j];*n=*n+1;}flag=0;}}void select(Haffman *ha,int *s1,int *s2,int n){int i,w=100;for(i=1;i<2*n;i++){if((ha+i)->parent==0&&(ha+i)->weight!=0)if((ha+i)->weight<w){*s1=i;w=(ha+i)->weight;}}(ha+(*s1))->parent=1;w=100;for(i=1;i<2*n;i++){if((ha+i)->parent==0&&(ha+i)->weight!=0)if((ha+i)->weight<w){*s2=i;w=(ha+i)->weight;}}(ha+(*s2))->parent=1;}void haffuman(char **c2, Haffman * haff,cc c1[100],int n) {int i,s1,s2,j,t;char *c;for(i=1;i<n+1;i++){(haff+i)->lchild=0;(haff+i)->parent=0;(haff+i)->rchild=0;(haff+i)->weight=c1[i-1].n;(haff+i)->c=c1[i-1].a;}for(i=1+n;i<2*n;i++){(haff+i)->lchild=0;(haff+i)->parent=0;(haff+i)->rchild=0;(haff+i)->weight=0;(haff+i)->c='\0';}for(i=n+1;i<2*n;i++){select(haff,&s1,&s2,n);(haff+i)->weight=(haff+s1)->weight+(haff+s2)->weight;(haff+i)->lchild=s1;(haff+i)->rchild=s2;(haff+s1)->parent=i;(haff+s2)->parent=i;}c=(char*)malloc(10*sizeof(char));for(i=1;i<=n;i++){t=i;j=9;*(c+j)='\0';while((haff+t)->parent!=0){j=j-1;if((haff+(haff+t)->parent)->lchild==t)*(c+j)='0';else*(c+j)='1';t=(haff+t)->parent;}*(c2+i)=(char*)malloc((10-j)*sizeof(char));strcpy(*(c2+i),(c+j));}}void main(){Haffman *haff;char **c2;cc c1[100];int i, n=0;char c[100];printf("请输入电文\n");scanf("%s",&c);input(c,c1,&n);haff=(Haffman *)malloc(2*n*sizeof(Haffman ));c2=(char**)malloc((n+1)*sizeof(char *));haffuman(c2, haff, c1,n);printf("字符权编码 \n");for(i=1;i<=n;i++){printf("%c ",(haff+i)->c);printf("%d ",(haff+i)->weight);printf("%s\n", *(c2+i));printf("\n");}}程序运行截图:。
HUFFMAN树及编码1.需求分析随机输入一篇英文文章(或读一个TXT文件),生成并显示HUFFMAN树,输出每个字母的HUFFMAN编码,判断ASCII编码与HUFFMAN编码对本篇报文长度节省效果。
(a) 输入的形式为键盘随机输入,输入的字符串长度在10000以内;(b) 输出HUFFMAN树的存储结构;(c) 程序功能为输入英文文章中每个字母的HUFFMAN编码,以及与ASCLL 码编码长度的比较结果;(d) 测试数据:正确的输入一篇英文文章,会输出各个字母的HUFFMAN编码。
错误的输入即其输出输入错误。
2. 概要设计首先统计英文文章中各个字母的个数作为权值,再统计出现的字母的个数,以决定所构造赫夫曼树的节点个数,之后便开始构造赫夫曼树,再构造每个节点的哈夫曼编码。
所设计的抽象数据类型如下:typedef struct{unsigned int weight; //权值unsigned int parent, lchild, rchild; //双亲,左孩子,右孩子} HTNode, * HuffmanTree;typedef char * * HuffmanCode;所设计的函数如下:int min(HuffmanTree HT, int i) 找出所有权值中最小的那个。
void Select(HuffmanTree HT, int i, int &s1, int &s2) 找出每次最小的两个权值最小的权值。
Status HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n) 构造赫夫曼树并构造每个字母的赫夫曼编码。
void PrintHT(HuffmanTree HT, int n)输出赫夫曼树的存储结构。
3. 详细设计int min(HuffmanTree HT, int i){int j, flag = 1;unsigned int k = 10000;for(j = 1; j <= i; j++){if(HT[j].weight < k && HT[j].parent == 0){k = HT[j].weight, flag = j;}//if}HT[flag].parent = 1;return flag;}void Select(HuffmanTree HT, int i, int &s1, int &s2){int j;s1 = min(HT, i);s2 = min(HT, i);if(s1 > s2){j = s1;s1 = s2;s2 = j;}}Status HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n) {int s1, s2, i, start, f;char *cd;HuffmanTree p = NULL;//p是工作指针,指向赫夫曼树中的结点if(n <= 1){return ERROR;}int m = 2 * n - 1; //n个字符构造的赫夫曼树共有m = 2*n-1个结点printf("->待构造的赫夫曼树共有2 ×%d - 1 = %d个结点\n", n, m);if(!(HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode))))//申请赫夫曼树结点占用的内存空间,0号单元不用{exit(OVERFLOW);}//ifprintf("->赫夫曼树共分配了%d个结点空间,其中包含一个不用的0号单元\n", m + 1);//printf("->初始化所有叶子节点的权值,父亲和孩子:\n");for(p = HT + 1, i = 1; i <= n; ++i, ++p, ++w){p->weight = *w;p->parent = 0;//双亲初始值为0,表示此结点还没有被选择最小的算法选择过p->lchild = 0;//左右孩子初始化为0,表示空p->rchild = 0;}for(; i <= m; i++, p++){p->weight = 0;p->parent = 0;p->lchild = 0;p->rchild = 0;}for(i = n + 1; i <= m; ++i){Select(HT, i - 1, s1, s2);HT[s1].parent = i;//选出的两个权值最小的结点的双亲就是即将生成的结点HT[s2].parent = i;HT[i].lchild = s1;//即将生成的结点左孩子是s1,右孩子是s2,HT[i].rchild = s2;//因为s1比s2先选,所以s1总是小于等于s2HT[i].weight = HT[s1].weight + HT[s2].weight;//即将生成结点的权值就是两个权值最小的结点的权值之和}if(!(HC = (HuffmanCode)malloc((n + 1) * sizeof(char *)))){exit(OVERFLOW);}//ifif(!(cd = (char *)malloc(n * sizeof(char)))){exit(OVERFLOW);}cd[n-1] = '\0';for(int i = 1; i <= n; ++i){start = n - 1;for(int c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent){if(HT[f].lchild == c){cd[--start] = '0';}//ifelse //叶子结点根结点的右孩子{cd[--start] = '1';}//else}if(!(HC[i] = (char *)malloc((n - start) * sizeof(char)))){exit(OVERFLOW);}strcpy(HC[i], &cd[start]);//printf("->叶子节点%d的赫夫曼编码为:%s\n", i, HC[i]);}free(cd);return OK;}//HuffmanCodingvoid PrintHT(HuffmanTree HT, int n){int m = 2 * n - 1;printf("\n+-------------------------------------------------------------+\n");printf("| 赫夫曼树HT的存储结构|\n");printf("+----------+----------+----------+--------------+-------------+\n");printf("| 结点编号| weight | parent | leftchild | rightchild |\n");printf("+----------+----------+----------+--------------+-------------+\n");for(int i = 1; i <= m; i++){printf("| %4d | %4d | %4d | %4d | %4d |\n",i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);printf("+----------+----------+----------+--------------+-------------+\n");}}for(int i = 0; i < len; i++){if(str[i] == 'A')a[65]++;else if(str[i] == 'B')a[66]++;else if(str[i] == 'C')a[67]++;else if(str[i] == 'D')a[68]++;else if(str[i] == 'E')a[69]++;else if(str[i] == 'F')a[70]++;else if(str[i] == 'G')a[71]++;else if(str[i] == 'H')a[72]++;else if(str[i] == 'I')a[73]++;else if(str[i] == 'J')a[74]++;else if(str[i] == 'K')a[75]++;else if(str[i] == 'L')a[76]++;else if(str[i] == 'M')a[77]++;else if(str[i] == 'N')a[78]++//部分统计字母代码主程序首先随机输入一篇英文文章,再统计各字母个数,再调用HuffmanCoding(HT, HC, w, n)函数,此函数又会调用void Select(HuffmanTree HT, int i, int &s1, int &s2)函数,而此函数又会调用int min(HuffmanTree HT, int i)函数,构造完成后便调用PrintHT(HT,n)函数输出赫夫曼树的存储结构。