(在VC++上调试通过)哈夫曼树编码上机实验
哈夫曼编码的实验报告

哈夫曼编码的实验报告哈夫曼编码的实验报告一、引言信息的传输和存储是现代社会中不可或缺的一部分。
然而,随着信息量的不断增加,如何高效地表示和压缩信息成为了一个重要的问题。
在这个实验报告中,我们将探讨哈夫曼编码这一种高效的信息压缩算法。
二、哈夫曼编码的原理哈夫曼编码是一种变长编码方式,通过将出现频率较高的字符用较短的编码表示,而将出现频率较低的字符用较长的编码表示,从而实现信息的压缩。
它的核心思想是利用统计特性,将出现频率较高的字符用较短的编码表示,从而减少整体编码长度。
三、实验过程1. 统计字符频率在实验中,我们首先需要统计待压缩的文本中各个字符的出现频率。
通过遍历文本,我们可以得到每个字符出现的次数。
2. 构建哈夫曼树根据字符频率,我们可以构建哈夫曼树。
哈夫曼树是一种特殊的二叉树,其中每个叶子节点代表一个字符,并且叶子节点的权值与字符的频率相关。
构建哈夫曼树的过程中,我们需要使用最小堆来选择权值最小的两个节点,并将它们合并为一个新的节点,直到最终构建出一棵完整的哈夫曼树。
3. 生成编码表通过遍历哈夫曼树,我们可以得到每个字符对应的编码。
在遍历过程中,我们记录下每个字符的路径,左边走为0,右边走为1,从而生成编码表。
4. 进行编码和解码在得到编码表后,我们可以将原始文本进行编码,将每个字符替换为对应的编码。
编码后的文本长度将会大大减少。
为了验证编码的正确性,我们还需要进行解码,将编码后的文本还原为原始文本。
四、实验结果我们选取了一段英文文本作为实验数据,并进行了哈夫曼编码。
经过编码后,原始文本长度从1000个字符减少到了500个字符。
解码后的文本与原始文本完全一致,验证了哈夫曼编码的正确性。
五、讨论与总结哈夫曼编码作为一种高效的信息压缩算法,具有广泛的应用前景。
通过将出现频率较高的字符用较短的编码表示,哈夫曼编码可以在一定程度上减小信息的存储和传输成本。
然而,哈夫曼编码也存在一些局限性,例如对于出现频率相近的字符,编码长度可能会相差较大。
数据结构(C语言版)实验报告(哈夫曼树)

《数据结构与算法》实验报告一、需求分析1.问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工通道(及可以双向传输信息的通道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼的编/译码系统。
2.基本要求一个完整的系统应具有以下功能:(1)I:初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:译码(Decoding)。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5)T:印哈夫曼树(Tree printing)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示出,同时将此字符形式的哈夫曼树写入文件TreePrint中。
3.测试数据(1)利用教科书例6-2中的数据调试程序。
(2)用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。
4,实现提示(1)编码结果以文本方式存储在文件CodeFile中。
(2)用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”表示退出运行Quit。
请用户键入一个选择功能符。
此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
(3)在程序的一次执行过程中,第一次执行I、D或C命令之后,哈夫曼树已经在内存了,不必再读入。
哈夫曼编码实验报告

... ... 哈夫曼编码器实验报告学院:计算机学院班级:计科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);}运行结果:六、所遇问题及心得体会本次试验中所遇到的主要问题为哈弗曼编码的算法,以及整个变量的控制。
c语言 哈夫曼树哈夫曼编码

c语言哈夫曼树哈夫曼编码哈夫曼树(Huffman Tree)和哈夫曼编码(Huffman Coding)是由戴维·哈夫曼在1952年为数据压缩应用而发明的。
哈夫曼编码是一种前缀编码,即任何字符的编码都不是另一个字符的编码的前缀。
在编码学中,哈夫曼编码是一种可变长度编码,其中较常见或较频繁的字符使用较短的编码,而较少见或较不频繁的字符使用较长的编码。
这种编码是由哈夫曼树生成的,哈夫曼树是一种特殊的二叉树,其每个节点的权重等于其左子树和右子树的权重之和。
在C语言中实现哈夫曼树和哈夫曼编码可能涉及以下步骤:1、定义哈夫曼树的节点结构。
每个节点可能包括字符,权重(或频率),以及左孩子和右孩子的指针。
ctypedef struct huffman_node {char character;unsigned int frequency;struct huffman_node *left, *right;} huffman_node;2、创建哈夫曼树。
首先,你需要计算每个字符的频率,然后根据这些频率创建一个哈夫曼树。
这个过程可能涉及使用优先队列(最小堆)来找出频率最小的两个节点,然后将它们合并为一个新的节点,新节点的频率是这两个节点的频率之和。
然后,将新节点放回队列中,重复这个过程直到队列中只剩下一个节点,这个节点就是你的哈夫曼树的根节点。
3、使用哈夫曼树生成哈夫曼编码。
从根节点开始,对于每个字符,左子树代表0,右子树代表1。
你可以遍历哈夫曼树,为每个字符生成其对应的哈夫曼编码。
4、实现解码。
给定一个哈夫曼编码,你可以通过遍历哈夫曼树来解码它。
对于每个位,如果是0,你跟随左子树,如果是1,你跟随右子树。
当你到达一个叶节点时,你就找到了对应的字符。
以上只是一个大致的步骤,具体的实现可能会根据你的需求和具体情况有所不同。
数字图像实验 哈夫曼编码的方法和实现1234

实验八哈夫曼编码的方法和实现一、实验目的1.掌握哈夫曼编码的基本理论和算法流程;2. 用VC++6.0编程实现图像的哈夫曼编码。
二、实验内容1.画出哈夫曼编码的算法流程;2.用VC++6.0编程实现哈夫曼编码。
三、实验步骤(1)启动VC++6.0,打开Dip工程。
(2)在菜单栏→insert→resouce→dialog→new,在对话框模版的非控制区点击鼠标右键,在弹出的对话框中选properties,设置为ID:IDD_DLG_Huffman,C标题:哈夫曼编码表。
(3)在弹出的对话框中,添加如下的按钮等控件:(4)在ResourceView栏中→Menu→选IDR_DIPTYPE ,如图在图像编码菜单栏下空的一栏中,右键鼠标,在弹出的对话框中选属性properties,在弹出的对话框中,进行如下的设置(5)右击哈夫曼编码表菜单栏,在建立的类向导中进行如下设置(6)在DipDoc.cpp中找到void CDipDoc::OnCodeHuffman()添加如下代码void CDipDoc::OnCodeHuffman(){int imgSize;imgSize = m_pDibObject->GetWidth()*m_pDibObject->GetHeight();//在点处理CPointPro类中创建用来绘制直方图的数据CPointPro PointOperation(m_pDibObject );int *pHistogram = PointOperation.GetHistogram();//生成一个对话框CHistDlg类的实例CDlgHuffman HuffmanDlg;//将绘制直方图的数据传递给CHistDlg对话框类的公有成员变量m_pnHistogramif( pHistogram != NULL ){//设置直方图数据指针HuffmanDlg.m_fFreq = pHistogram;HuffmanDlg.m_iSizeImage = imgSize;if(m_pDibObject->GetNumBits() >= 8)HuffmanDlg.m_iLeafNum=256;elseHuffmanDlg.m_iLeafNum=m_pDibObject->GetNumBits();}//显示对话框if ( HuffmanDlg.DoModal() != IDOK)return;delete [] pHistogram;}(7)在DipDoc.cpp中添加#include "DlgHuffman.h"(8)将DlgHuffman.h、DlgHuffman.cpp文件拷贝到当前工程目录文件里面;并添加到当前工程。
哈夫曼树及哈夫曼编码的算法实现c语言

哈夫曼树及哈夫曼编码的算法实现c语言1.引言1.1 概述哈夫曼树及哈夫曼编码是数据压缩和编码中常用的重要算法。
哈夫曼树由大卫·哈夫曼于1952年提出,用于根据字符出现的频率构建一种最优的前缀编码方式。
而哈夫曼编码则是根据哈夫曼树构建的编码表将字符进行编码的过程。
在现代通信和计算机领域,数据传输和存储中往往需要大量的空间。
为了有效利用有限的资源,减少数据的存储和传输成本,数据压缩成为一个重要的技术。
而哈夫曼树及哈夫曼编码正是数据压缩中常用的技术之一。
哈夫曼树的概念及原理是基于字符的频率和概率进行构建的。
在哈夫曼树中,字符出现频率越高的节点越接近根节点,出现频率越低的节点离根节点越远。
这种构建方式保证了哈夫曼树的最优性,即最小化编码的总长度。
哈夫曼编码的算法实现是根据哈夫曼树构建的编码表进行的。
编码表中,每个字符都与一段二进制编码相对应。
在进行数据压缩和解压缩时,通过查表的方式将字符转化为相应的二进制编码,或将二进制编码解析为原始字符。
本文旨在介绍哈夫曼树及哈夫曼编码的概念和原理,并通过C语言实现算法。
通过深入理解哈夫曼树及哈夫曼编码的实现过程,可以更好地理解数据压缩和编码的原理,为后续的研究和应用提供基础。
接下来,我们将首先介绍哈夫曼树的概念和原理,然后详细讲解哈夫曼编码的算法实现。
最后,我们将总结哈夫曼树及哈夫曼编码的重要性,并提出对哈夫曼树和哈夫曼编码进一步研究的方向。
让我们一起深入探索哈夫曼树及哈夫曼编码的奥秘吧!1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分主要介绍了本文的组织结构和各个章节的内容概述,以帮助读者更好地理解全文的逻辑结构和内容安排。
首先,本文包括引言、正文和结论三个部分。
引言部分主要对哈夫曼树及哈夫曼编码的算法实现进行了概述,包括相关的概念、原理和目的。
正文部分则深入介绍了哈夫曼树的概念和原理,以及哈夫曼编码的算法实现。
最后,结论部分对本文的主要内容进行了总结,并提出了对哈夫曼树和哈夫曼编码的进一步研究方向。
哈夫曼树上机实验报告

霍夫曼树实验目的:掌握结构体、指针及二叉树的生成、遍历等操作掌握霍夫曼编码/译码的原理。
基本要求:熟练掌握树的操作。
程序实现:程序第一遍统计原数据中各字符出现的频率,利用得到的频率值创建哈夫曼树,并把树的信息保存起来,以便解压时创建同样的哈夫曼树进行解压;第二遍,根据第一遍扫描得到的哈夫曼树进行编码,并把编码后的码字存储。
要点分析:题目中涉及的主要知识点:1、本程序参考霍夫曼算法(由给定的权值构造赫夫曼树):(1)由给定的n个权值{w0, w1, w2, …, wn-1},构造具有n棵二叉树的集合F ={T0, T1, T2, …, Tn-1},其中每一棵二叉树Ti只有一个带有权值wi的根结点,其左、右子树均为空。
(2)重复以下步骤, 直到F中仅剩下一棵树为止:①在F中选取两棵根结点的权值最小的二叉树, 做为左、右子树构造一棵新的二叉树。
置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。
②在F中删去这两棵二叉树。
③把新的二叉树加入F。
2、用构造赫夫曼树以完成赫夫曼编码:把d1,d2,…, dn 作为叶子结点,把w1,w2,…,wn作为叶子结点的权,构造赫夫曼树。
在赫夫曼树中结点的左分支赋0,右分支赋1,从根结点到叶子结点的路径上的数字拼接起来就是这个叶子结点字符的编码。
3、译码的过程是分解电文中的字符串,从根出发,按字符‘0’或‘1’确定找左孩子或右孩子,直至叶子节点,便求得该子串相应的字符。
心得体会:通过本次实验,我熟练掌握了结构体、指针及二叉树的生成、遍历等操作,掌握了霍夫曼编码和译码的原理,熟练掌握树的操作,尤其是对霍夫曼树有了更深刻的理解。
同时,在编写代码的过程中方,对字符串的相关知识进行了回顾。
代码#include<stdio.h>#include<stdlib.h>#include<string.h>typedef struct{int weight;int parent,lchild,rchild;int sign;}HTNode,*HuffmanTree;typedef char * *HuffmanCode;void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n,char *s);void select(HuffmanTree &HT,int i,int &s1,int &s2);void creatHuffmanTree(int *w,char *s,char *r);void pr(HuffmanCode &HC,char r[],char s,char a[]);void HuffmanYM(HuffmanCode &HC,char r[],char a[],int n,HuffmanTree &HT);void HuffmanPass(HuffmanCode &HC,char r[],int n,HuffmanTree &HT);int main(){char s[100];char r[100];char a[100]="a";int w[100];int n,p;HuffmanTree HT;HuffmanCode HC;printf("请输入进行编码的字符串\n");scanf("%s",s);p=strlen(s);if(p!=1)creatHuffmanTree(w,s,r);printf("进行编码......\n");if(p!=1)HuffmanCoding(HT,HC,w,strlen(r)-1,r);else printf("%c的霍夫曼编码是: %c\n",s[0],'0');printf("霍夫曼码序列为:\n");if(p!=1)for(int i=0;i<strlen(s);i++)pr(HC,r,s[i],a);printf("\n");n=strlen(r)-1;if(p==1)printf("0\n");printf("霍夫曼编码进行译码:\n");if(p==1)printf("%c",s[0]);else HuffmanYM(HC,r,a,n,HT);printf("\n");printf("先序遍历输出叶子节点\n");if(p==1){printf("%c\n",s[0]);}else HuffmanPass(HC,r,n,HT);return 0;}void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int w[],int n,char s[]) {int s1,s2,f,c;int m,i,l;int start;char cd[101];if(n<1)return;l=strlen(s);m=2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));HT[0].weight=10000;for (i=1;i<=n;++i){HT[i].weight=w[i-1];HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;HT[i].sign=0;}for(;i<=m+1;++i){HT[i].weight=0;HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;HT[i].sign=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;}HC=(HuffmanCode)malloc((n+1)*sizeof(char *));cd[n-1]='\0';for(i=1;i<=n;i++){start=n;c=i;for(f=HT[i].parent;f!=0;f=HT[f].parent){if(HT[f].lchild==c){start--;cd[start]='0';}else{start--;cd[start]='1';}c=f;}HC[i]=(char *)malloc((n-start)*sizeof(char));for(int a=0;a<n-start;a++){HC[i][a]=cd[start+a];}HC[i][a]='\0';printf("%c的霍夫曼编码是: %s\n",s[i],HC[i]);}}void select(HuffmanTree &HT,int i,int &s1,int &s2){s1=0;s2=0;for(int j=1;j<=i;j++){if(HT[j].parent==0)if(HT[j].weight<=HT[s1].weight)s1=j;else continue;}else continue;}for(j=1;j<=i;j++){if(j==s1)continue;elseif(HT[j].parent==0){if(HT[j].weight<=HT[s2].weight)s2=j;else continue;}else continue;}}void creatHuffmanTree(int w[],char s[],char r[]) {int g=1;int q=0;r[0]='0';r[1]=s[0];w[0]=1;for(int e=1;e<strlen(s);e++){for(int k=1;k<=g;k++){if(r[k]==s[e]){w[k-1]++;q=1;}else continue;}if(q==0){r[++g]=s[e];w[g-1]=1;q=0;}r[++g]='\0';}void pr(HuffmanCode &HC,char r[],char s,char a[]){for(int i=1;i<strlen(r);i++){if(r[i]==s){printf("%s",HC[i]);strcat(a,HC[i]);}else continue;}}void HuffmanYM(HuffmanCode &HC,char r[],char a[],int n,HuffmanTree &HT) {int e=strlen(a);int k=0;int f=2*n-1;char b[10]="1";for(int j=1;j<=e;j++){if(HT[f].lchild!=0||HT[f].rchild!=0){b[k]=a[j];k++;if(a[j]=='1')f=HT[f].rchild;else if(a[j]=='0')f=HT[f].lchild;}else{for(int s=1;s<=n;s++){if(strcmp(HC[s],b)==0){printf("%c",r[s]);break;}else continue;}for(int u=0;u<10;u++)b[u]='\0';k=0;f=2*n-1;j=j-1;}}}void HuffmanPass(HuffmanCode &HC,char r[],int n,HuffmanTree &HT) {int f,k=0;char b[10]="a";f=2*n-1;HT[f].sign=0;if(HT[f].lchild==0&&HT[f].rchild==0)return;do{if(HT[f].lchild==0&&HT[f].rchild==0){for(int s=1;s<=n;s++){if(strcmp(HC[s],b)==0){printf("%c",r[s]);break;}else continue;}b[k--]='\0';HT[f].sign=2;f=HT[f].parent;}if(HT[f].sign==0){b[k]='0';HT[f].sign++;f=HT[f].lchild;k++;}elseif(HT[f].sign==1){b[k]='1';HT[f].sign++;f=HT[f].rchild;k++;}elseif(HT[f].sign==2){f=HT[f].parent;b[k--]='\0';}}while(f!=0);printf("%\n");}。
哈夫曼树编码实验报告

哈夫曼树编码实验报告哈夫曼树编码实验报告引言:哈夫曼树编码是一种常用的数据压缩算法,通过对数据进行编码和解码,可以有效地减小数据的存储空间。
本次实验旨在探究哈夫曼树编码的原理和应用,并通过实际案例验证其有效性。
一、哈夫曼树编码原理哈夫曼树编码是一种变长编码方式,根据字符出现的频率来确定不同字符的编码长度。
频率较高的字符编码较短,频率较低的字符编码较长,以达到最佳的数据压缩效果。
1.1 字符频率统计首先,需要对待编码的数据进行字符频率统计。
通过扫描数据,记录每个字符出现的次数,得到字符频率。
1.2 构建哈夫曼树根据字符频率构建哈夫曼树,频率较低的字符作为叶子节点,频率较高的字符作为父节点。
构建哈夫曼树的过程中,需要使用最小堆来维护节点的顺序。
1.3 生成编码表通过遍历哈夫曼树,从根节点到每个叶子节点的路径上的左右分支分别赋予0和1,生成对应的编码表。
1.4 数据编码根据生成的编码表,将待编码的数据进行替换,将每个字符替换为对应的编码。
编码后的数据长度通常会减小,实现了数据的压缩。
1.5 数据解码利用生成的编码表,将编码后的数据进行解码,恢复原始数据。
二、实验过程与结果为了验证哈夫曼树编码的有效性,我们选择了一段文本作为实验数据,并进行了以下步骤:2.1 字符频率统计通过扫描文本,统计每个字符出现的频率。
我们得到了一个字符频率表,其中包含了文本中出现的字符及其对应的频率。
2.2 构建哈夫曼树根据字符频率表,我们使用最小堆构建了哈夫曼树。
频率较低的字符作为叶子节点,频率较高的字符作为父节点。
最终得到了一棵哈夫曼树。
2.3 生成编码表通过遍历哈夫曼树,我们生成了对应的编码表。
编码表中包含了每个字符的编码,用0和1表示。
2.4 数据编码将待编码的文本数据进行替换,将每个字符替换为对应的编码。
编码后的数据长度明显减小,实现了数据的压缩。
2.5 数据解码利用生成的编码表,将编码后的数据进行解码,恢复原始文本数据。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//注意:在输入n个权值时,每输入一个权值都要按一个回车键
#include"iostream"
#include"stdlib.h"
#include"stdio.h"
#include"malloc.h"
#include"string.h"
using namespace std;
#define UNIT_MAX 65535
typedef struct TNode
{ int parent;
unsigned int weight;
unsigned int lchild;
unsigned int rchild;
} *HuffmanTree, HTNode;
typedef char **HuffmanCode;
int select(HuffmanTree t, int i)//返回根节点中权值最小的树的根节点的序号函数select()调用{
int j;
int find=0;
int k = UNIT_MAX;//取K为不小于可能的值
for (j = 1; j < i; j++) //在t数组的前i-1个数组元素中寻找一个parent值为0且权值最小的if ((int)t[j].weight < k && t[j].parent == 0)
{
k = t[j].weight;
find=j;
}
t[find].parent = 1;
return find;
}
char** HuffmanCoding(HTNode HT[], char* HC[], int w[], int n)
{ //w存放n个字符的权值的一维数组,n为叶子个数;构造哈夫曼树HT;HC数组用以存放求得的n个字符的编码
int m, i, s1, s2, start;
int c, f;
HuffmanTree p;
char* cd;
m = 2 * n - 1; //n即为叶子数n0,由二叉树性质,n0=n2+1,故树中结点数为*n-1
for (i = 1, p = HT + 1; i <= n; ++i, ++p, ++w)
{//n个叶子结点赋初值,n个叶子最初为n个根结点,p指向HT[1],HT[0]不用(*p).weight = *w;
(*p).parent = 0;
(*p).lchild = 0;
(*p).rchild = 0;
}
for (i=n+1; i <= m; i++, p++) //n-1个附加的父亲结点赋初值
{
(*p).weight = 0;
(*p).parent = 0;
(*p).lchild = 0;
(*p).rchild = 0;
}
for (i = n + 1; i <= m; i++) // 第i次循环时为第i个结点选择两个儿子结点s1与s2 { s1 = select(HT,i); // 在i-1棵子树中也即HT[1..i-1]中选择无父亲(parent为0)且权值最小
s2 = select(HT,i); //的两个结点(其序号分别为s1和s2)。
HT[i].weight = HT[s1].weight + HT[s2].weight;//i结点为s1结点和s2结点的父亲结点
HT[i].lchild = s1; //建立左儿子关系
HT[i].rchild = s2; //建立右儿子关系
HT[s1].parent = HT[s2].parent = i;//建立父亲关系
}
//哈夫曼树HT构造完毕
cd = (char*)malloc(n * sizeof(char)); // 申请存放编码的工作数组(n个字符空间) cd[n - 1] = '\0'; // 当前字符的编码工作数组的最后一个单元存放一个结束符。
for (i = 1; i <= n; ++i)
{ //第i次循环时求第i个叶子(字符)的哈夫曼编码
start = n - 1; // start指向cd数组(即工作数组)中编码结束符的位置
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
{ // 从叶子到根逆向求编码
start--;
if (HT[f].lchild == c) cd[start] = '0'; //若当前结点是其父亲的左孩子,赋值'0'
else cd[start] = '1'; //若当前结点是其父亲的右孩子,则赋值'1'
}
HC[i] = (char*)malloc(n* sizeof(char)); //为存放第i个字符的编码申请空间
strcpy(HC[i], &cd[start]); //从cd复制编码(串)到HC,函数strcpy在头文件string.h中}// i从1到n求n个叶子的编码结束
return HC; //求编码结束,释放工作数组cd所占用的存储空间,将HC数组作为结果返回}// char** HuffmanCoding结束
void main()
{
HTNode *HT;
char** HC;
int* w, n, i;
printf("输入叶子节点个数:\n");
scanf("%d", &n);
if (n <= 1) return;
printf("输入各个叶节点所对应的权值, 每输入一个权值都要按一个回车键:\n");
w = (int*)malloc(n * sizeof(int));
HT = (HuffmanTree)malloc((2*n-1) * sizeof(HTNode));// 0号单元未用
HC = (HuffmanCode)malloc((n+1) * sizeof(char*));// 0号单元未用
for (i = 0; i < n ; i++)
scanf("%d",&w[i]); //每输入一个值按一个回车键
HuffmanCoding(HT, HC, w, n);
cout<<n<<"个叶子的编码为:\n";
for(i=1;i<=n;i++)
{ //打印n个字符的编码
printf("%s\n",HC[i]);
}
}//main结束
输出结果:。