哈夫曼实验报告

合集下载

bmp哈夫曼编码实验报告

bmp哈夫曼编码实验报告

多媒体技术与基础实验——huffman编码实验一:Huffman编码一、实验内容1、了解BMP图像的格式,实现BMP图片格式的数据域及文件头的分离2、熟悉Huffman编码原理3、用C语言使用Huffman编码算法对给定图像文件进行编码二、设计思路1、BMP文件的前54字节是与具体图像无关的文件头信息,进行哈夫曼编码时不需要对这部分进行编码。

2、哈夫曼编码基于图像统计特征的变长编码方法概率小的符号用较长的码字表示,概率大的符号用较短的码字表示。

3、霍夫曼编码的步骤:1)根据待编码的符号串,统计各个符号的概率;2)根据符号的概率统计特征,构建霍夫曼编码表,即计算每个符号的编码结果;3)用得到的编码表对符号序列进行编码。

三、相关知识1、Huffman Tree的定义假设有n个权值{w1,w2,w3......wn},试构造一棵有n个叶子节点的二叉树(节点总数为m=2*n-1),每个叶子带权值为wi,其中WPL(树带权路径)最小的二叉树成为Huffman树或者最优二叉树。

2、如何构造Huffman Tree(1).根据给点的n个权值{w1,w2,w3.....wn}构成n棵二叉树的集合F={T1,T2,T3......Tn},其中每棵二叉树只有个带有权值Wi的根节点,其左右子树为空。

(2).在F中选取两棵根结点的权值最小的树作为左右子树构造一个新二叉树,新根权值为左右子树权值之和。

(3).在F中delete掉这两棵树,插入新二叉树到F中。

(4).重复(2)和(3),直到F中只含一棵树,此数位Huffman Tree。

四、实验结果平均码字长度为7.57,编码效率为0.9967。

实验结果分析:哈夫曼编码是动态变长编码,对每一个图像,临时建立概率统计表和编码树,算法速度比静态编码慢,但压缩效果最好。

但是对具有很多不同颜色的图像时,哈夫曼编码的平均码字长度将增大,编码效率将下降,故需改进哈夫曼算法,例如采用截断哈夫曼算法等。

哈夫曼编码的实验报告

哈夫曼编码的实验报告

哈夫曼编码的实验报告哈夫曼编码的实验报告一、引言信息的传输和存储是现代社会中不可或缺的一部分。

然而,随着信息量的不断增加,如何高效地表示和压缩信息成为了一个重要的问题。

在这个实验报告中,我们将探讨哈夫曼编码这一种高效的信息压缩算法。

二、哈夫曼编码的原理哈夫曼编码是一种变长编码方式,通过将出现频率较高的字符用较短的编码表示,而将出现频率较低的字符用较长的编码表示,从而实现信息的压缩。

它的核心思想是利用统计特性,将出现频率较高的字符用较短的编码表示,从而减少整体编码长度。

三、实验过程1. 统计字符频率在实验中,我们首先需要统计待压缩的文本中各个字符的出现频率。

通过遍历文本,我们可以得到每个字符出现的次数。

2. 构建哈夫曼树根据字符频率,我们可以构建哈夫曼树。

哈夫曼树是一种特殊的二叉树,其中每个叶子节点代表一个字符,并且叶子节点的权值与字符的频率相关。

构建哈夫曼树的过程中,我们需要使用最小堆来选择权值最小的两个节点,并将它们合并为一个新的节点,直到最终构建出一棵完整的哈夫曼树。

3. 生成编码表通过遍历哈夫曼树,我们可以得到每个字符对应的编码。

在遍历过程中,我们记录下每个字符的路径,左边走为0,右边走为1,从而生成编码表。

4. 进行编码和解码在得到编码表后,我们可以将原始文本进行编码,将每个字符替换为对应的编码。

编码后的文本长度将会大大减少。

为了验证编码的正确性,我们还需要进行解码,将编码后的文本还原为原始文本。

四、实验结果我们选取了一段英文文本作为实验数据,并进行了哈夫曼编码。

经过编码后,原始文本长度从1000个字符减少到了500个字符。

解码后的文本与原始文本完全一致,验证了哈夫曼编码的正确性。

五、讨论与总结哈夫曼编码作为一种高效的信息压缩算法,具有广泛的应用前景。

通过将出现频率较高的字符用较短的编码表示,哈夫曼编码可以在一定程度上减小信息的存储和传输成本。

然而,哈夫曼编码也存在一些局限性,例如对于出现频率相近的字符,编码长度可能会相差较大。

数据结构哈夫曼编码实验报告

数据结构哈夫曼编码实验报告

数据结构哈夫曼编码实验报告一、实验目的:通过哈夫曼编、译码算法的实现,巩固二叉树及哈夫曼树相关知识的理解掌握,训练学生运用所学知识,解决实际问题的能力。

二、实验内容:已知每一个字符出现的频率,构造哈夫曼树,并设计哈夫曼编码。

1、从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树。

2、打印每一个字符对应的哈夫曼编码。

3、对从终端读入的字符串进行编码,并显示编码结果。

4、对从终端读入的编码串进行译码,并显示译码结果。

三、实验方案设计:(对基本数据类型定义要有注释说明,解决问题的算法思想描述要完整,算法结构和程序功能模块之间的逻辑调用关系要清晰,关键算法要有相应的流程图,对算法的时间复杂度要进行分析)1、算法思想:(1)构造两个结构体分别存储结点的字符及权值、哈夫曼编码值:(2)读取前n个结点的字符及权值,建立哈夫曼树:(3)根据哈夫曼树求出哈夫曼编码:2、算法时间复杂度:(1)建立哈夫曼树时进行n到1次合并,产生n到1个新结点,并选出两个权值最小的根结点:O(n²);(2)根据哈夫曼树求出哈夫曼编码:O(n²)。

(3)读入电文,根据哈夫曼树译码:O(n)。

四、该程序的功能和运行结果:(至少有三种不同的测试数据和相应的运行结果,充分体现该程序的鲁棒性)1、输入字符A,B,C,D,E,F及其相应权值16、12、9、30、6、3。

2、输入字符F,E,N,G,H,U,I及其相应权值30、12、23、22、12、7、9。

3、输入字符A,B,C,D,E,F,G,H,I,G及其相应权值19、23、25、18、12、67、23、9、32、33。

数据结构大作业-哈夫曼编码实验报告

数据结构大作业-哈夫曼编码实验报告

一.构造过程①统计可知,字符串全长共59个字符,其中字符‘A’-‘F’的出现频数及对应概率(保留两位小数)如图所示:②将每个字符出现概率作为权重,则对于上述给定的6个权值{25,15,14,20,17,9},依次构造6棵只有根节点的二叉树,共同构成森林F;③在森林F中,选取权重最小和次小的两颗树,分别作为新二叉树的左子树、右子树,且该树根节点权值赋左右子树权值之和;④从森林F中删除已选中的两棵子树,把新得到的二叉树加入F 中;⑤重复③④,直到森林F中仅留下一棵树时,得到最终的哈夫曼树HF如图所示:⑥对上述哈夫曼树,将其树中的每个左分支赋0、右分支赋1,则从根结点开始到叶子结点,各分支路径分别得到对应的二进制串,即为给定的每个字符的哈夫曼编码。

二、代码实现源代码如下:#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>#include <string.h>#define N 6 //指定的编码字符数#define M (2 * N - 1) //HT结点数#define MAXWEIGHT 100typedef struct { //哈夫曼树的存储表示int weight;int parent, lchild, rchild;}HTNode;typedef HTNode HuffmanTree[M + 1];typedef char* HuffmanCode[N + 1]; //哈夫曼编码表void Select(HuffmanTree HT, int n, int& s1, int& s2);void CreateHuffmanTree(HuffmanTree& HT, int* w, int n); void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC); void PrintHC(HuffmanCode HC, char ch[]);int main() {HuffmanTree HT;HuffmanCode HC;int w[N + 1];char ch[N + 1];printf("Please input %d characters & its weight(e.g. A 25):\n", N);for (int i = 1; i <= N; i++) {scanf("%c %d", &ch[i], &w[i]);getchar();}CreateHuffmanTree(HT, w, N);CreateHuffmanCode(HT, HC);PrintHC(HC, ch);return 0;}void Select(HuffmanTree HT, int n, int& s1, int& s2) { int i, min = 0, temp = MAXWEIGHT;for (i = 1; i <= n; i++) {if (!HT[i].parent) {if (temp > HT[i].weight) {temp = HT[i].weight;min = i; //最小值作为新树左子树}}}s1 = min;for (i = 1, min = 0, temp = MAXWEIGHT; i <= n; i++) { if ((!HT[i].parent) && i != s1) {if (temp > HT[i].weight) {temp = HT[i].weight;min = i; //次小值作为新树右子树}}}s2 = min;}void CreateHuffmanTree(HuffmanTree& HT, int* w, int n) { //创建哈夫曼树HTint i, s1, s2;if (n <= 1) return; //树为空或仅有根节点for (i = 1; i <= M; ++i) { //初始化HT[i].weight = w[i];HT[i].parent = 0;HT[i].lchild = 0;HT[i].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;HT[i].rchild = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}}void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC) {int i, start, c, f;char cd[N];cd[N - 1] = '\0'; //编码结束符for (i = 1; i <= N; i++) { //对于第i个待编码字符即第i个带权值的叶子节点start = N - 1; //开始start指向结束符位置c = i;f = HT[i].parent; //f指向当前结点的双亲while (f) { //从叶上溯,到根节点跳出if (HT[f].lchild == c)cd[--start] = '0'; //左孩子elsecd[--start] = '1'; //右孩子c = f;f = HT[f].parent;}HC[i] = new char[N - start];strcpy(HC[i], &cd[start]); //复制结果到编码表,用于输出}}void PrintHC(HuffmanCode HC, char ch[]) { //打印哈夫曼编码表for (int i = 1; i <= N; i++)printf("\n%c: %s\n", ch[i], HC[i]);}三,输出各个字母的哈夫曼编码:四、算法分析1、哈夫曼编码是最优前缀编码:对包括N个字符的数据文件,分别以它们的出现概率构造哈夫曼树,利用该树对应的哈夫曼编码对报文进行编码,得到压缩后的最短二进制编码;2、算法自底而上地构造出对应最优编码的二叉树HT,它从n个叶子结点开始,识别出最低权重的两个对象,并将其合并;当合并时,新对象的权重设置为原两个对象权值之和,一共执行了|n| - 1次合并操作;3、是贪心算法:每次选择均为当下的最优选择,通过合并来构造最优树得到对应的哈夫曼编码;4、复杂度:①时间复杂度:有n个终端节点,构成的哈夫曼树总共有2n-1个节点,Select函数的时间复杂度为O(n),嵌套for循环,因此建立哈夫曼树的时间复杂度为O(n^2),创建哈弗曼编码表的时间复杂度为O(n^2);②空间复杂度:算法中临时占用存储空间大小为数组第0号空间,其耗费的空间复杂度为O(1)。

哈夫曼编码实验报告

哈夫曼编码实验报告

哈夫曼编码实验报告
几个相关的基本概念:
1.路径:从树中一个结点到另一个结点之间的分支序列构成两个节点间的路径。

2.路径长度:路径上的分支的条数称为路径长度。

3.树的路径长度:从树根到每个结点的路径长度之和称为树的路径长度。

4.结点的权:给树中结点赋予一个数值,该数值称为结点的权。

5.带权路径长度:结点到树根间的路径长度与结点的权的乘积,称为该结点的带权路径长度。

6.树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记为WPL 。

7.最优二叉树:在叶子个数n以及各叶子的权值确定的条件下,树的带权路径长度WPL值最低的二叉树称为最优二叉树。

哈夫曼树的建立
由哈夫曼最早给出的建立最优二叉树的带有一般规律的算法,俗
称哈夫曼算法。

描述如下:
1)初始化:根据给定的n个权值(W1,W2,…,Wn),构造n棵二叉树的森林集合F={T1,T2,…,Tn},其中每棵二叉树Ti只有一个权值为Wi的根节点,左右子树均为空。

2)找最小树并构造新树:在森林集合F中选取两棵根的权值最小的树做为左右子树构造一棵新的二叉树,新的二叉树的根结点为新增加的结点,其权值为左右子树的权值之和。

3)删除与插入:在森林集合F中删除已选取的两棵根的权值最小的树,同时将新构造的二叉树加入到森林集合F中。

4)重复2)和3)步骤,直至森林集合F中只含一棵树为止,这颗树便是哈夫曼树,即最优二叉树。

由于2)和3)步骤每重复一次,删除掉
两棵树,增加一棵树,所以2)和3)步骤重复n-1次即可获得哈夫曼树。

哈夫曼编码实验报告

哈夫曼编码实验报告

... ... 哈夫曼编码器实验报告学院:计算机学院班级:计科0801班:王宇宏学号:04081027(27)一.实验目的练习树和哈夫曼树的有关操作,和各个算法程序,理解哈夫曼树的编码和译码二.实验环境Microsoft visual c++三、问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。

但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。

对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编码/译码系统。

试为这样的信息收发站写一个哈夫曼编码的编码/译码器。

四、需求分析(1)初始化;从终端输入字符集的大小n,以及n个字符和n个权值建立哈夫曼树。

(2)输出哈夫曼树,及各字符对应的编码。

(3)编码:利用建好的哈夫曼树,对输入的待发送电文进行编码。

同时输入原文及编码串。

(4)译码:利用建好的哈夫曼树,对输入的已接收电文进行译码。

同时输入编码串及原文。

五、概要设计#include <iostream.h>#include <iomanip.h>#include <string.h>#include <malloc.h>#include <stdio.h>//typedef int TElemType;const int UINT_MAX=1000;char str[50];typedef struct{int weight,K;int parent,lchild,rchild;}HTNode,* HuffmanTree;typedef char **HuffmanCode;//-----------全局变量-----------------------HuffmanTree HT;HuffmanCode HC;int w[50],i,j,n;char z[50];int flag=0;int numb=0// -----------------求哈夫曼编码-----------------------struct cou{char data;int count;}cou[50];int min(HuffmanTree t,int i){ // 函数void select()调用int j,flag;int k=UINT_MAX; // 取k为不小于可能的值,即k为最大的权值1000 for(j=1;j<=i;j++)if(t[j].weight<k&&t[j].parent==0)k=t[j].weight,flag=j;t[flag].parent=1;return flag;}//--------------------slect函数----------------------void select(HuffmanTree t,int i,int &s1,int &s2){ // s1为最小的两个值中序号小的那个int j;s1=min(t,i);s2=min(t,i);if(s1>s2){j=s1;s1=s2;s2=j;}}// --------------算法6.12--------------------------void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){ // w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HCint m,i,s1,s2,start;//unsigned c,f;int c,f;HuffmanTree p;char *cd;if(n<=1)return;//检测结点数是否可以构成树m=2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); // 0号单元未用 for(p=HT+1,i=1;i<=n;++i,++p,++w){p->weight=*w;p->parent=0;p->lchild=0;p->rchild=0;}for(;i<=m;++i,++p)p->parent=0;for(i=n+1;i<=m;++i) // 建哈夫曼树{ // 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2select(HT,i-1,s1,s2);HT[s1].parent=HT[s2].parent=i;HT[i].lchild=s1;HT[i].rchild=s2;HT[i].weight=HT[s1].weight+HT[s2].weight;}// 从叶子到根逆向求每个字符的哈夫曼编码HC=(HuffmanCode)malloc((n+1)*sizeof(char*));// 分配n个字符编码的头指针向量([0]不用)cd=(char*)malloc(n*sizeof(char)); // 分配求编码的工作空间cd[n-1]='\0'; // 编码结束符for(i=1;i<=n;i++){ // 逐个字符求哈夫曼编码start=n-1; // 编码结束符位置for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)// 从叶子到根逆向求编码if(HT[f].lchild==c)cd[--start]='0';elsecd[--start]='1';HC[i]=(char*)malloc((n-start)*sizeof(char)); // 为第i个字符编码分配空间strcpy(HC[i],&cd[start]); // 从cd复制编码(串)到HC }free(cd); // 释放工作空间}//--------------------- 获取报文并写入文件---------------------------------int InputCode(){//cout<<"请输入你想要编码的字符"<<endl;FILE *tobetran;if((tobetran=fopen("tobetran.txt","w"))==NULL){cout<<"不能打开文件"<<endl;return 0;}cout<<"请输入你想要编码的字符"<<endl;gets(str);fputs(str,tobetran);cout<<"获取报文成功"<<endl;fclose(tobetran);return strlen(str);}//--------------初始化哈夫曼链表--------------------------------- void Initialization(){ int a,k,flag,len;a=0;len=InputCode();for(i=0;i<len;i++){k=0;flag=1;cou[i-a].data=str[i];cou[i-a].count=1;while(i>k){if(str[i]==str[k]){a++;flag=0;}k++;if(flag==0)break;}if(flag){for(j=i+1;j<len;j++){if(str[i]==str[j])++cou[i-a].count;}}}n=len-a;for(i=0;i<n;i++){ cout<<cou[i].data<<" ";cout<<cou[i].count<<endl;}for(i=0;i<=n;i++){*(z+i)=cou[i].data;*(w+i)=cou[i].count;}HuffmanCoding(HT,HC,w,n);//------------------------ 打印编码-------------------------------------------cout<<"字符对应的编码为:"<<endl;for(i=1;i<=n;i++){puts(HC[i]);}//-------------------------- 将哈夫曼编码写入文件------------------------cout<<"下面将哈夫曼编码写入文件"<<endl<<"...................."<<endl;FILE *htmTree;char r[]={' ','\0'};if((htmTree=fopen("htmTree.txt","w"))==NULL){cout<<"can not open file"<<endl;return;}fputs(z,htmTree);for(i=0;i<n+1;i++){fprintf(htmTree,"%6d",*(w+i));fputs(r,htmTree);}for(i=1;i<=n;i++){fputs(HC[i],htmTree);fputs(r,htmTree);}fclose(htmTree);cout<<"已将字符与对应编码写入根目录下文件htmTree.txt中"<<endl<<endl;}//---------------------编码函数---------------------------------void Encoding(){cout<<"下面对目录下文件tobetran.txt中的字符进行编码"<<endl; FILE *tobetran,*codefile;if((tobetran=fopen("tobetran.txt","rb"))==NULL){cout<<"不能打开文件"<<endl;}if((codefile=fopen("codefile.txt","wb"))==NULL){cout<<"不能打开文件"<<endl;}char *tran;i=99;tran=(char*)malloc(100*sizeof(char));while(i==99){if(fgets(tran,100,tobetran)==NULL){cout<<"不能打开文件"<<endl;break;}for(i=0;*(tran+i)!='\0';i++){for(j=0;j<=n;j++){if(*(z+j-1)==*(tran+i)){fputs(HC[j],codefile);if(j>n){cout<<"字符错误,无法编码!"<<endl; break;}}}}}cout<<"编码工作完成"<<endl<<"编码写入目录下的codefile.txt中"<<endl<<endl;fclose(tobetran);fclose(codefile);free(tran);}//-----------------译码函数---------------------------------void Decoding(){cout<<"下面对根目录下文件codefile.txt中的字符进行译码"<<endl;FILE *codef,*txtfile;if((txtfile=fopen("txtfile.txt","w"))==NULL){cout<<"不能打开文件"<<endl;}if ((codef=fopen("codefile.txt","r"))==NULL){cout<<"不能打开文件"<<endl;}char *work,*work2,i2;int i4=0,i,i3;unsigned long length=10000;work=(char*)malloc(length*sizeof(char));fgets(work,length,codef);work2=(char*)malloc(length*sizeof(char));i3=2*n-1;for(i=0;*(work+i-1)!='\0';i++){i2=*(work+i);if(HT[i3].lchild==0){*(work2+i4)=*(z+i3-1);i4++;i3=2*n-1;i--;}else if(i2=='0') i3=HT[i3].lchild;else if(i2=='1') i3=HT[i3].rchild;}*(work2+i4)='\0';fputs(work2,txtfile);cout<<"译码完成"<<endl<<"容写入根目录下的文件txtfile.txt中"<<endl<<endl;free(work);free(work2);fclose(txtfile);fclose(codef);}//-----------------------打印编码的函数----------------------void Code_printing(){cout<<"下面打印根目录下文件CodePrin.txt中编码字符"<<endl; FILE * CodePrin,* codefile;if((CodePrin=fopen("CodePrin.txt","w"))==NULL){cout<<"不能打开文件"<<endl;return;}if((codefile=fopen("codefile.txt","r"))==NULL){cout<<"不能打开文件"<<endl;return;}char *work3;work3=(char*)malloc(51*sizeof(char));do{if(fgets(work3,51,codefile)==NULL){cout<<"不能读取文件"<<endl;break;}fputs(work3,CodePrin);puts(work3);}while(strlen(work3)==50);free(work3);cout<<"打印工作结束"<<endl<<endl;fclose(CodePrin);fclose(codefile);}//------------------------------- 打印译码函数---------------------------------------------void Code_printing1(){cout<<"下面打印根目录下文件txtfile.txt中译码字符"<<endl;FILE * CodePrin1,* txtfile;if((CodePrin1=fopen("CodePrin1.txt","w"))==NULL){cout<<"不能打开文件"<<endl;return;}if((txtfile=fopen("txtfile.txt","r"))==NULL){cout<<"不能打开文件"<<endl;return;}char *work5;work5=(char*)malloc(51*sizeof(char));do{if(fgets(work5,51,txtfile)==NULL){cout<<"不能读取文件"<<endl;break;}fputs(work5,CodePrin1);puts(work5);}while(strlen(work5)==50);free(work5);cout<<"打印工作结束"<<endl<<endl;fclose(CodePrin1);fclose(txtfile);}//------------------------打印哈夫曼树的函数----------------------- void coprint(HuffmanTree start,HuffmanTree HT){if(start!=HT){FILE * TreePrint;if((TreePrint=fopen("TreePrint.txt","a"))==NULL){cout<<"创建文件失败"<<endl;return;}numb++;//该变量为已被声明为全局变量coprint(HT+start->rchild,HT);cout<<setw(5*numb)<<start->weight<<endl;fprintf(TreePrint,"%d\n",start->weight);coprint(HT+start->lchild,HT);numb--;fclose(TreePrint);}}void Tree_printing(HuffmanTree HT,int w){HuffmanTree p;p=HT+w;cout<<"下面打印哈夫曼树"<<endl;coprint(p,HT);cout<<"打印工作结束"<<endl;}//------------------------主函数------------------------------------void main(){char choice;while(choice!='q'){ cout<<"\n******************************"<<endl;cout<<" 欢迎使用哈夫曼编码解码系统"<<endl;cout<<"******************************"<<endl;cout<<"(1)要初始化哈夫曼链表请输入'i'"<<endl; cout<<"(2)要编码请输入'e'"<<endl;cout<<"(3)要译码请输入'd'"<<endl;cout<<"(4)要打印编码请输入'p'"<<endl;cout<<"(5)要打印哈夫曼树请输入't'"<<endl;cout<<"(6)要打印译码请输入'y'"<<endl;if(flag==0)cout<<"\n请先初始化哈夫曼链表,输入'i'"<<endl;cin>>choice;switch(choice){case 'i':Initialization();break;case 'e':Encoding();break;case 'd':Decoding();break;case 'p':Code_printing();break;case 't':Tree_printing(HT,2*n-1);break;case 'y':Code_printing1();break;default:cout<<"input error"<<endl;}}free(z);free(w);free(HT);}运行结果:六、所遇问题及心得体会本次试验中所遇到的主要问题为哈弗曼编码的算法,以及整个变量的控制。

信息论课程实验报告—哈夫曼编码

信息论课程实验报告—哈夫曼编码
else if(T[j].weight < T[*p2].weight)
*p2 = j;
}
}
void CreateHuffmanTree(HuffmanTree T)
{
int i,p1,p2;
InitHuffmanTree(T);
InputWeight(T);
for(i = n;i < m;i++)
4)依次继续下去,直至信源最后只剩下两个信源符号为止,将这最后两个信源符号分别用二元码符号“0”和“1”表示;
5)然后从最后—级缩减信源开始,进行回溯,就得到各信源符号所对应的码符号序列,即相应的码字。
四、实验目的:
(1)进一步熟悉Huffman编码过程;(2)掌握C语言递归程序的设计和调试技术。以巩固课堂所学编码理论的知识。
#include "stdio.h"
#include "stdlib.h"
#include <float.h>
#include <math.h>
#define n 8
#define m 2*n-1
typedef struct
{
float weight;
int lchild,rchild,parent;
}
}
void InputWeight(HuffmanTree T)
{
float temp[n] = {0.20,0.18,0.17,0.15,0.15,0.05,0.05,0.05};
for(int i = 0;i < n;i++)
T[i].weight = temp[i];
}

哈夫曼树的实验报告1

哈夫曼树的实验报告1

哈夫曼树的实验报告1一、需求分析1、本演示程序实现Haffman编/译码器的作用,目的是为信息收发站提供一个编/译系统,从而使信息收发站利用Haffman编码进行通讯,力求达到提高信道利用率,缩短时间,降低成本等目标。

系统要实现的两个基本功能就是:①对需要传送的数据预先编码;②对从接收端接收的数据进行译码;2、本演示程序需要在终端上读入n个字符(字符型)及其权值(整形),用于建立Huffman树,存储在文件hfmanTree.txt中;如果用户觉得不够清晰还可以打印以凹入表形式显示的Huffman树;3、本演示程序根据建好的Huffman树,对文件的文本进行编码,结果存入文件CodeFile中;然后利用建好的Huffman树将文件CodeFile中的代码进行译码,结果存入文件TextFile中;最后在屏幕上显示代码(每行50个),同时显示对CodeFile中代码翻译后的结果;4、本演示程序将综合使用C++和C语言;5、测试数据:(1)教材例6-2中数据:8个字符,概率分别是0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,可将其的权值看为5,29,7,8,14,23,3,11(2)用下表给出的字符集和频度的实际统计数据建立Haffman树,并实现以下报文的编码和一、概要设计1、设定哈夫曼树的抽象数据类型定义ADT Huffmantree{数据对象:D={a i| a i∈Charset,i=1,2,3,……n,n≥0}数据关系:R1={< a i-1, a i >| a i-1, a i∈D, i=2,3,……n}基本操作:Initialization(&HT,&HC,w,n,ch)操作结果:根据n个字符及其它们的权值w[i],建立Huffman树HT,用字符数组ch[i]作为中间存储变量,最后字符编码存到HC中;Encodeing(n)操作结果:根据建好的Huffman树,对文件进行编码,编码结果存入到文件CodeFile 中Decodeing(HT,n)操作结果:根据已经编译好的包含n个字符的Huffman树HT,将文件的代码进行翻译,结果存入文件T extFile中} ADT Huffmantree1)主程序模块void main(){输入信息,初始化;选择需要的操作;生成Huffman树;执行对应的模块程序;输出结果;}2)编码模块——根据建成的Huffman树对文件进行编码;3)译码模块——根据相关的Huffman树对编码进行翻译;各模块的调用关系如图所示二、详细设计1、树类型定义typedef struct {unsigned int weight; //权值char ch1; //储存输入的字符unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree;2、编码类型定义typedef char **HuffmanCode;哈夫曼编译器的基本操作设置如下Initialization(HuffmanTree &HT,HuffmanCode &HC,int *w,int &n,char *ch) //根据输入的n个字符及其它们的权值w[i],建立Huffman树HT,用字符数组ch[i]作为中间存储变量存储编码,最后转存到HC中;Encodeing(int n)//根据建好的包含n个字符的Huffman树,对文件进行编码,编码结果存入到文件CodeFile中Decodeing(HuffmanTree HT,int n)//根据已经编译好的包含n个字符的Huffman树HT,对文件的代码进行翻译,结果存入文件TextFile中基本操作操作的算法主函数及其他函数的算法void select(HuffmanTree HT,int n,int &s1,int &s2){ //依次比较,从哈夫曼树的中parent为0的节点中选择出两个权值最小的if(!HT[i].parent&&!HT[S1]&&!HT[S2]){if(HT[i].weight<ht[s1].weight){< p="">s2=s1; s1=i;}else if(HT[i].weight<ht[s2].weight&&i!=s1)< p=""> s2=i;}3、函数的调用关系图三、调试分析Encodeing Decoding Print PrintTreeInitialization1、本次实习作业最大的难点就是文件的读和写,这需要充分考虑到文件里面的格式,例如空格,换行等等,由于不熟悉C++语言和C语言的文件的输入和输出,给编程带来了很大的麻烦;2、原本计划将文本中的换行格式也进行编码,也由于设计函数比较复杂,而最终放弃;3、一开始考虑打印哈夫曼树的凹入表时是顺向思维,希望通过指针的顺序变迁来实现打印,但问题是从根结点到叶子结点的指针不是顺序存储的,所以未能成功,后来查找相关资料,最终利用递归的方法解决问题;4、程序中的数组均采用了动态分配的方法定义,力求达到减少空间的浪费;5、时间的复杂度主要是由查树这个步骤决定,因为无论是编码还是译码都需要对Huffman树进行查找和核对,但考虑到英文字母和空格也就是27个字符,影响不是很大;6、程序无论在屏幕显示还有文件存储方面都达到了不错的效果;7、程序不足的地方就是在文件文本格式方面处理得还是不够,或许可以通过模仿WORD的实现来改善。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

哈夫曼实验报告
哈夫曼实验报告
一、引言
信息压缩是计算机科学领域中一项重要的研究课题。

在信息传输和存储过程中,如何将数据压缩成更小的体积,既可以节省存储空间,又可以提高传输效率,
一直是学术界和工业界的关注焦点。

而哈夫曼编码作为一种常用的压缩算法,
具有广泛的应用前景。

本实验旨在通过实际操作,深入了解哈夫曼编码的原理
和实现过程。

二、实验目的
1. 了解哈夫曼编码的基本原理;
2. 学习如何构建哈夫曼树;
3. 实现哈夫曼编码和解码的算法;
4. 分析哈夫曼编码在实际应用中的优势和局限性。

三、实验过程
1. 数据收集和处理
在本实验中,我们选择了一段英文文本作为实验数据。

首先,我们对文本进行
了预处理,去除了标点符号和空格,并将所有字母转换为小写。

这样可以简化
后续的编码和解码过程。

2. 构建哈夫曼树
根据收集到的数据,我们统计了每个字符出现的频率,并按照频率从小到大的
顺序构建了一个字符频率表。

接着,我们使用哈夫曼树的构建算法,将字符频
率表转化为一棵哈夫曼树。

在构建过程中,我们采用了最小堆来维护频率表中
的字符节点,并通过合并最小的两个节点来构建树的分支。

3. 哈夫曼编码和解码
在哈夫曼树构建完成后,我们根据树的结构和字符频率表,生成了每个字符的
哈夫曼编码。

编码过程中,我们采用了深度优先遍历的方法,从根节点到叶子
节点依次生成编码。

同时,我们还实现了哈夫曼解码算法,通过根据编码逐步
遍历哈夫曼树,将编码转换为原始字符。

四、实验结果
经过实验,我们成功地实现了哈夫曼编码和解码的算法,并对实验数据进行了
压缩和解压缩操作。

通过比较压缩前后数据的大小,我们发现使用哈夫曼编码后,数据的体积显著减小。

这说明哈夫曼编码在信息压缩方面具有很好的效果。

同时,我们还对不同数据集进行了实验,发现哈夫曼编码对于频率较高的字符
可以实现更好的压缩效果。

这是因为哈夫曼编码可以根据字符的频率分配不同
长度的编码,使得频率较高的字符使用较短的编码,从而达到更好的压缩效果。

然而,哈夫曼编码也存在一些局限性。

首先,编码和解码的过程需要构建哈夫
曼树,这需要消耗一定的时间和空间。

对于较大的数据集,构建哈夫曼树可能
会导致性能下降。

此外,哈夫曼编码对于频率较低的字符,编码长度较长,可
能会导致压缩效果不佳。

五、结论
本实验通过实际操作,深入了解了哈夫曼编码的原理和实现过程。

我们成功地
实现了哈夫曼编码和解码的算法,并验证了其在信息压缩方面的有效性。

哈夫
曼编码作为一种常用的压缩算法,在实际应用中具有广泛的应用前景。

然而,
我们也应该认识到其局限性,不同的数据集可能需要选择不同的压缩算法来实
现更好的效果。

相关文档
最新文档