哈夫曼树编码译码源代码及测试文件

合集下载

哈夫曼编码算法实现完整版

哈夫曼编码算法实现完整版

实验三树的应用一. 实验题目:树的应用——哈夫曼编码二. 实验内容:利用哈夫曼编码进行通信可以大大提高信道的利用率,缩短信息传输的时间,降低传输成本。

根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求哈夫曼编码。

要求:从键盘输入若干字符及每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各个字符进行哈夫曼编码,最后打印输出字符及对应的哈夫曼编码。

三、程序源代码 :#include <iostream.h>#include <fstream.h>#include <string.h>#include <stdlib.h>typedef struct{char data;int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char * * HuffmanCode;void Select(HuffmanTree &HT,int n,int m){HuffmanTree p=HT;int tmp;for(int j=n+1;j<=m;j++){int tag1,tag2,s1,s2;tag1=tag2=32767;for(int x=1;x<=j-1;x++){ if(p[x].parent==0&&p[x].weight<tag1){tag1=p[x].weight;s1=x;}}for(int y=1;y<=j-1;y++){ if(p[y].parent==0&&y!=s1&&p[y].weight<tag2){ tag2=p[y].weight;s2=y;}}if(s1>s2) //将选出的两个节点中的序号较小的始终赋给s1{ tmp=s1; s1=s2; s2=tmp;}p[s1].parent=j;p[s2].parent=j;p[j].lchild=s1;p[j].rchild=s2;p[j].weight=p[s1].weight+p[s2].weight;}}void HuffmanCoding(HuffmanTree &HT,int n,char *w1,int*w2) {int m=2*n-1;if(n<=1)return;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));HuffmanTree p=HT;for(int i=1;i<=n;i++){ p[i].data=w1[i-1];p[i].weight=w2[i];p[i].parent=p[i].lchild=p[i].rchild=0;}for(;i<=m;i++){ p[i].weight=p[i].parent=p[i].lchild=p[i].rchild=0; }Select(HT,n,m);ofstream outfile; //生成 hfmTree 文件outfile.open("hfmTree.txt",ios::out);for (i=1;i<=m;i++){outfile<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i].lchild<<"\t"<<HT[i].rchild<<"\t"<<endl;}outfile.close();cout<<" 初始化结果已保存在hfmTree 文件中 \n";}void ToBeTree()// 将正文写入文件ToBeTree中{ofstream outfile;outfile.open("ToBeTree.txt",ios::out);outfile<<"THIS PROGRAM IS MYFA VORITE";outfile.close();}void Encoding(HuffmanTree &HT,int n)// 编码{HuffmanCode HC;HC=(HuffmanCode)malloc((n+1)*sizeof(char *));char *cd;cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';for(int k=1;k<=n;k++){ int start=n-1;for(int c=k,f=HT[k].parent;f!=0;c=f,f=HT[f].parent){if(HT[f].lchild==c) cd[--start]='0';else cd[--start]='1';}HC[k]=(char *)malloc((n-start)*sizeof(char));strcpy(HC[k],&cd[start]);}cout<<" 输出哈夫曼编码 :"<<endl;for(int h=1;h<=n;h++)// 输出编码{cout<<HT[h].data<<":";cout<<HC[h];cout<<" ";if (h%8==0) cout<<endl;}cout<<endl<<" 输出正文编码 : "<<endl;ToBeTree();//读取 TOBETREE文件里的正文,并进行编码 fstream infile;infile.open("ToBeTree.txt",ios::in);char s[80];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();fstream outfile;outfile.open("CodeFile.txt",ios::out);int count=0;for (h=0;s[h]!='\0';h++){ for(k=1;k<=n;k++)if (s[h]==HT[k].data){ cout<<HC[k];cout<<" ";count++;outfile<<HC[k];break;}if (count%9==0) cout<<endl;// 每输出 7 个换行}outfile.close();cout<<"\n 编码结果已保存在文件CodeFile 中.";cout<<endl;}void Decoding(HuffmanTree &HT,int n)// 译码{int f=2*n-1;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();int i=0;int j=0;fstream outfile;outfile.open("TextFile.txt",ios::out);while(s[i]!='\0'){ f=2*n-1;while(HT[f].lchild!=0)// 以 f 对应的节点的左孩子的值==0作为结束{if (s[j]=='0')f=HT[f].lchild;else f=HT[f].rchild;j++;}i=j;cout<<HT[f].data;outfile<<HT[f].data;}outfile.close();cout<<"\n 译码结果已保存在文件TextFile中.";cout<<endl;}void Print()// 印代码文件{ int count=0;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));for(int i=0;s[i]!='\0';i++){ cout<<s[i];count++;if (count%50==0) cout<<endl; // 在终端上每行显示 50 个代码}}infile.close();cout<<endl;}char menu()// 菜单函数{ cout<<" 功能菜单如下 : "<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<"I: 初始化 (Initialization)"<<endl;cout<<"E:编码 (Encoding)"<<endl; cout<<"D:译码 (Decoding)"<<endl; cout<<"P:印代码文件 (Print)"<<endl; cout<<"Q:退出 (Exit)"<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<"请输入功能字符 :";char ch;cin>>ch;return ch;}void main(){ int n;int Array[100]; charcArray[100];HuffmanTree HT;cout<<" 输入 n 个字符 :";cin.getline(cArray,100);n=strlen(cArray);cout<<" 一共 "<<n<<" 个字符 .\n";cout<<" 依次输入各个字符的权值:"<<endl;for (int i=1;i<=n;i++)cin>>Array[i];int tag;char x=menu();while(1){ switch (x){case 'I':HuffmanCoding(HT,n,cArray,Array);break;case 'E':Encoding(HT,n);break;case 'D':Decoding(HT,n);break;case 'P':Print();break;case 'Q':tag=0;cout<<"结束 "<<endl;break;default:cout<<" 你输入错误 !"<<endl;}if(tag==0) break;cout<<"y( 继续 ) or n(退出 )"<<endl;char ch;cin>>ch;if (ch=='y'){ cout<<" 请输入功能字符 :";char c;cin>>c;x=c;}else exit(1);}}测试数据:用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的译码和编码 :" THIS PROGRAM IS MY FAVORITE".字符空格AB C D E F G H I J K LM频度 186 64 13 2232103 211547571532 20字符 NOP QRSTUV WXYZ频度 576315148518023818 1161四.测试结果:如图一所示五. 实验体会通过本次实验,尤其在自己对程序的调试过程中,感觉对树的存储结构,终结状态,还有编码,译码的过程都有了比较清晰的认识。

数据结构哈夫曼树编码及译码的实现实验报告

数据结构哈夫曼树编码及译码的实现实验报告

实验:哈夫曼树编码及译码的实现一.实验题目给定字符集的HUFFMANN编码与解码,这里的字符集及其字符频数自己定义,要求输出个字符集的哈夫曼编码及给定的字符串的哈夫曼码及译码结果。

二.实验原理首先规定构建哈夫曼树,然后进行哈夫曼树的编码,接着设计函数进行字符串的编码过程,最后进行哈夫曼编码的译码。

首先定义一个结构体,这个结构体定义时尽可能的大,用来存放左右的变量,再定义一个地址空间,用于存放数组,数组中每个元素为之前定义的结构体。

输入n个字符及其权值。

构建哈夫曼树:在上述存储结构上实现的哈夫曼算法可大致描述为:1.首先将地址空间初始化,将ht[0…n-1]中所有的结点里的指针都设置为空,并且将权值设置为0.2.输入:读入n个叶子的权值存于向量的前n个分量中。

它们是初始森林中n个孤立的根结点上的权值。

3.合并:对森林中的树共进行n-1次合并,所产生的新结点依次放入向量ht的第i个分量中。

每次合并分两步:①在当前森林ht[0…i-1]的所有结点中,选取权最小和次小的两个根结点[s1]和 [s2]作为合并对象,这里0≤s1,s2≤i-1。

②将根为ht[s1]和ht[s2]的两棵树作为左右子树合并为一棵新的树,新树的根是新结点ht[i]。

具体操作:将ht[s1]和ht[s2]的parent置为i,将ht[i]的lchild和rchild分别置为s1和s2 .新结点ht[i]的权值置为ht[s1]和ht[s2]的权值之和。

4.哈夫曼的编码:约定左子为0,右子为1,则可以从根结点到叶子结点的路径上的字符组成的字符串作为该叶子结点的编码。

当用户输入字母时。

就在已经找好编码的编码结构体中去查找该字母。

查到该字母就打印所存的哈夫曼编码。

接着就是完成用户输入0、1代码时把代码转成字母的功能。

这是从树的头结点向下查找,如果当前用户输入的0、1串中是0则就走向该结点的左子。

如果是1这就走向该结点的右结点,重复上面步骤。

哈弗曼编码及译码算法(包含源程序)

哈弗曼编码及译码算法(包含源程序)

哈夫曼编码一、实验目的1、掌握哈夫曼编码的二叉树结构表示方法;2、编程实现哈夫曼编码译码器;3、掌握贪心算法的设计策略。

二、实验任务①从文件中读取数据,构建哈夫曼树;②利用哈夫曼树,对输入明文进行哈夫曼编码;③利用哈夫曼树,对输入编码译码为明文。

三、实验设计方案1、结构体设计Huffman树:包括字符,权,父亲下标,左孩子下标,右孩子下标2、自定义函数设计①函数原型声明void input(); //读取文件字符、权值数据void huffman(); //建立huffman树void getcode(int i, char *str); //得到单个字符的huffman编码void encode(char ch); //将明文进行huffman编码void decode(char *str); //将huffman编码译为明文3、主函数设计思路:主函数实现实验任务的基本流程。

void main(){char ch;int i;char str[100];huffman(); //建立huffman树printf("请输入明文:"); //输入明文while((ch=getchar())!='\n')encode(ch); //得到huffman编码printf("\n");printf("\n请按字符编码对应表输入密文:\n");for(i=0;i<N;i++) //显示字符编码对应表{printf("%c:",ht[i].c);encode(ht[i].c);printf("\t");}scanf("%s",str); //输入编码串decode(str); //翻译成明文printf("\n");}程序代码:#include<stdio.h>struct shuju{char str;int data;};struct treenode{char c;int w;int f;int l;int r;};void sort(shuju a[],int num) {int i,j;shuju t;for(i=0;i<num;i++){int m=i;for(j=i+1;j<num;j++)if(a[j].data<a[m].data)m=j;t=a[m];a[m]=a[i];a[i]=t;}}void huffman(shuju a[],treenode htree[],int num) {int i,j,k,n;for(i=0; i<num; i++){htree[i].c=a[i].str;htree[i].w=a[i].data;htree[i].l=-1;htree[i].f=-1;htree[i].r=-1;}j=0;k=num;for(n=num;n<2*num-1;n++)htree[n].w=0;for(n=num;n<2*num-1;n++){int r=0,s=0;htree[n].l=-1;htree[n].f=-1;htree[n].r=-1;while(r<2){if((htree[k].w==0 || htree[k].w>htree[j].w) && j<num){ s=s+htree[j].w;if(r==0) htree[n].l = j;else htree[n].r=j;htree[j].f=n;j++;}else{s=s+htree[k].w;if(r==0) htree[n].l = k;else htree[n].r=k;htree[k].f=n;k++;}r++;}htree[n].w=s;}}int getcode(int i, int str[],treenode htree[]){int n,l=0;for(n=i;htree[n].f!=-1;n=htree[n].f){int m=htree[n].f;if(n==htree[m].l)str[l++]=0;elsestr[l++]=1;}return l;}void decode(treenode htree[],int c[],int n,int num){ int ch,m=0;ch=c[m];while(m<n){int i;for(i=2*num-2;htree[i].l!=-1;){if(ch==0)i=htree[i].l;elsei=htree[i].r;m++;ch=c[m];}printf("%c",htree[i].c);}}void main(){int str[1000],i,j,k,l,n,c[1000];FILE *fp;treenode htree[57];shuju a[29];char b[100];printf("请输入明文的长度n:");scanf("%d",&n);printf("请输入明文:");for(i=0;i<=n;i++)scanf("%c",&b[i]);fp=fopen("D:\\hanfuman\\shuju.txt","r"); for( i=0;i<29;i++){fscanf(fp,"%c%d\n",&a[i].str,&a[i].data);}fclose(fp);sort(a,29);huffman(a,htree,29);printf("输出译码是:");for(i=0;i<=n;i++){for(j=0;j<29;j++){if(b[i]==a[j].str){l=getcode(j,str,htree);for(k=l-1;k>=0;k--)printf("%d",str[k]);}}}printf("\n");printf("请输入译码的长度n:"); scanf("%d",&n);printf("请输入译码:");for(i=0;i<n;i++)scanf("%d",&c[i]);printf("输出解码为:");decode(htree,c,n,29);printf("\n");}D:\\hanfuman\\shuju.txt中的内容为:j 217z 309q 343x 505k 1183w 1328v 1531f 1899. 2058y 2815b 2918g 3061, 3069h 3724d 4186m 4241p 4283u 49105005c 6028s 6859l 6882n 7948o 8259t 8929r 9337i 9364a 10050e 11991 运行结果为:。

树的应用 哈夫曼编编码 和 译码

树的应用  哈夫曼编编码 和 译码

华%%%%%%%%%%%%%%%%%%学院数据结构实验报告2011~2012学年第二学期2011级计算机专业班级:学号:姓名:实验三树的应用一、实验题目:树的应用——哈夫曼编/译码二、实验内容:利用哈夫曼编码进行通信可以大大提高信道的利用率,缩短信息传输的时间,降低传输成本。

根据哈夫曼编码的原理,编写一个程序,在用户输入字符及权值的基础上求哈夫曼编码。

要求:(1)从键盘输入字符集(字母a~z,空格)共27个字符,以及出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,并输出数组ht[]的初态和终态。

(2)对各个字符进行哈夫曼编码,打印输出字符及对应的哈夫曼编码。

(3)编码:从键盘输入字符串,利用已建好的哈夫曼编码,实现该字符串的编码。

(4)(选作)译码:从键盘输入二进制串,利用已建好的哈夫曼编码,将二进制串还原为字符串。

三、程序源代码:typedef struct{char data;int weight;int parent;int lchild;int rchild;}HTNode;typedef struct{char cd[100];int start;}HCode;//这里保存字母对应的编码,我本来想用指向字符数组的指针数组,可是后来想到利用结构体更简单。

struct Codes{char ch;char codes[27];};#include<iostream.h>#include<stdio.h>#include<string.h>const int maxsize=100;//特色,动态编码void tongji(char str[],int *pinlv);void createHT(HTNode *ht,int n,int pinlv[]);void showHT(HTNode ht[],int n);void createHcode(HTNode ht[],HCode* hcd,int n);void showHCode(HCode hcd[],int n,int pinlv[]);//使字符与编码对应void matchcodes(HCode hcd[],int pinlv[],int n,Codes* code);void charToCode(Codes codes[],char *str);void codeToChar(Codes codes[]);void main(){cout<<"本例实现动态编码:根据输入的字符串建立编码规则,然后按此规则对输入的字符串进行编码,对输入的编码进行译码操作"<<endl;//输入cout<<"input a string"<<endl;char str[maxsize];gets(str);//统计int pinlv[27];int len=0;for(int i=0;i<27;i++)pinlv[i]=0;tongji(str,pinlv);for(int k=0;k<27;k++)if(pinlv[k]!=0)len++;cout<<len<<endl;// cout<<pinlv[26]<<endl;//构造哈夫曼树HTNode ht[199];createHT(ht,len,pinlv);//哈夫曼编码HCode hcd[27];createHcode(ht,hcd,len);showHCode(hcd,len,pinlv);//字符与编码对应匹配Codes codes[27];matchcodes(hcd,pinlv,len,codes);//char to codecharToCode(codes,str);// code to charcodeToChar(codes);}//这个函数有错误,已经改正void codeToChar(Codes codes[]){cout<<"根据上面输出的编码规则,请输入要译码的01编码(相邻编码要以逗号分割,以“#”结束)"<<endl;char str[100];gets(str);cout<<str<<"的译码为:"<<endl;char temp[27]; //保存每个字符的编码,每次要赋 0 啊int i,j;for(i=0,j=0;i<100;i++){if(str[i]!=','){temp[j]=str[i];j++;}else{temp[j]='\0';for(int k=0;k<27;k++){if(strcmp(codes[k].codes ,temp)==0){cout<<codes[k].ch <<" ";//cout.flush();break;}}j=0; //赋0 操作}if(str[i]=='#'){break;}}cout<<endl;}void charToCode(Codes codes[],char *str){char ch=*str;int k=0;cout<<str<<"的编码为:"<<endl;while(ch!='\0'){for(int i=0;i<27;i++){if(codes[i].ch ==ch)cout<<codes[i].codes<<",";}k++;ch=*(str+k);}cout<<endl;}//已经改进过的地方void matchcodes(HCode hcd[],int pinlv[],int n,Codes* codes) {int i,k,m;char ch='a';int p=0;char temp[27];for(int z=0;z<26;z++){temp[z]=' ';}temp[26]='\0';for(i=0;i<27;i++){if(pinlv[i]!=0){ch='a';ch=char(ch+i);if(ch>='a'&&ch<='z'){codes[p].ch =ch;//测试/* if(codes[p].ch==ch){cout<<"succss"<<endl;}*/}elsecodes[p].ch =' ';m=0;for(k=hcd[p].start;k<=n;k++){temp[m]=hcd[p].cd [k];m++;}//字符串必须给出结束符位置,否则会输出乱码啊temp[m]='\0';//codes[p]=temp;strcpy(codes[p].codes ,temp);// cout<<codes[p].ch;// cout<<codes[p].ch<<"-----"<<codes[p].codes<<endl;p++;}}}void showHCode(HCode hcd[],int n,int pinlv[]){int i,k;char ch='a';int p=0;cout<<"字符"<<" "<<"对应编码"<<endl;for(i=0;i<27;i++){//每次必须从字符'a'开始ch='a';////ch=char(ch+i);if(pinlv[i]!=0){if(ch>='a'&&ch<='z')cout<<ch<<" ";elsecout<<" "<<" ";for(k=hcd[p].start;k<=n;k++)cout<<hcd[p].cd [k];p++;cout<<endl;}}}void createHcode(HTNode ht[],HCode* hcd,int n) {int i,f,c;HCode hc;for(i=0;i<n;i++){//不是书上的hc.start =n;hc.start =n-1;c=i;f=ht[i].parent ;while(f!=-1){if(ht[f].lchild ==c)hc.cd [hc.start --]='0';elsehc.cd [hc.start --]='1';c=f;f=ht[f].parent ;}//最后一位必须赋值为结束符hc.cd[n]='\0';hc.start ++;hcd[i]=hc;}}void createHT(HTNode* ht,int n,int pinlv[]){for(int m=0;m<=2*n-1;m++)//初始化节点的所有与域值ht[m].parent =ht[m].lchild =ht[m].rchild =-1;char ch='a';int p=0;for(int z=0;z<27;z++)//循环27个字母(a-z和''),若频数大于0,就创建节点{if(pinlv[z]!=0){if(ch>='a'&&'z'>=ch){ht[p].data =ch;ht[p].weight =pinlv[ch-97];}else{ht[p].data =' ';ht[p].weight =pinlv[26];}p++;}ch=char (ch+1);}cout<<"ht[]初态输出 ";showHT(ht,n);int i,k,lnode,rnode;int min1,min2;for(i=n;i<2*n-1;i++){min1=min2=32767;lnode=rnode=-1;for(k=0;k<=i-1;k++){if(ht[k].parent ==-1){if(ht[k].weight <min1){min2=min1;rnode=lnode;min1=ht[k].weight ;lnode=k;}else if(ht[k].weight <min2){min2=ht[k].weight ;rnode=k;}}}ht[lnode].parent =i;ht[rnode].parent =i;ht[i].weight =ht[lnode].weight +ht[rnode].weight ;ht[i].lchild =lnode;ht[i].rchild =rnode;ht[i].data ='*';}cout<<"ht[]终态输出 ";showHT(ht,2*n-1);}void tongji(char str[],int *pinlv){char ch=*str;int k=1;while(ch!='\0'){ if(ch>='a'&&'z'>=ch)pinlv[ch-97]+=1;elsepinlv[26]+=1;ch=*(str+k);k++;}}void showHT(HTNode ht[],int n){ cout<<"节点信息如下:"<<endl;cout<<"data"<<" "<<"weig"<<" "<<"pare"<<" "<<"lchd"<<" "<<"rchd"<<endl;for(int i=0;i<n;i++){cout<<ht[i].data <<" "<<ht[i].weight <<" "<<ht[i].parent <<" "<<ht[i].lchild <<" "<<ht[i].rchild <<endl;}}四、测试结果:五、小结(包括收获、心得体会、存在的问题及解决问题的方法、建议等)注:内容一律使用宋体五号字,单倍行间距通过本次实验,我感觉到自己的程序编程细节问题必须注意:如使用gets()函数可接收带有空格的输入字符串;在进行编码译码时,必须注意,数组的上下界问题。

哈夫曼树的编码与译码

哈夫曼树的编码与译码

#include<stdio.h>#include<stdlib.h>#define n 4#define m 2*n-1#define maxval 32769typedef struct{float weight;int lchild,rchild,parent;char ch;}huftree;typedef struct{char bits[n];int start;}codetype;codetype code[n];huftree tree[m];void hufman(huftree tree[])//创建哈夫曼树{int i,j,p1,p2;char ch;float small1,small2,f;for(i=0;i<m;i++)//初始化所有结点{tree[i].parent=0;tree[i].lchild=0;tree[i].rchild=0;tree[i].weight=0.0;}printf("请输入结点的权值:\n");for(i=0;i<n;i++)//输入n个结点的权值{scanf("%f",&f);tree[i].weight=f;}printf("请输入结点的字符:\n");scanf("%c",&ch);for(i=0;i<n;i++)//输入n个结点的权值{scanf("%c",&ch);tree[i].ch=ch;}for(i=n;i<m;i++)//进行n-1次合并,产生n-1个新结点{p1=0,p2=0;small1=maxval;small2=maxval;for(j=0;j<=i-1;j++)//找出权值最小的两个根结点{if(tree[j].parent==0){if(tree[j].weight<small1)//改变最小权与次小权的位置{small2=small1;small1=tree[j].weight;p2=p1;p1=j;//锁定最小权的位置}else{if(tree[j].weight<small2){small2=tree[j].weight;p2=j;//锁定次小权的位置}}}}tree[p1].parent=i+1;//生成的新结点为最小权与次小权的双亲tree[p2].parent=i+1;tree[i].lchild=p1+1;tree[i].rchild=p2+1;tree[i].weight=tree[p1].weight+tree[p2].weight;}}void creathufcode(codetype code[])//由哈夫曼数构建哈夫曼编码{int i,c,p;codetype cd;for(i=0;i<n;i++)cd.start=n;c=i+1;p=tree[i].parent;while(p!=0){cd.start--;if(tree[p-1].lchild==c){cd.bits[cd.start]='0';}elsecd.bits[cd.start]='1';c=p;p=tree[p-1].parent;}code[i]=cd;}}void decode(codetype code[],huftree tree[])//依次读入电文,根据哈夫曼树译码{int i,b;int flag=-1;i=m-1;printf("请输入电文编码:");scanf("%d",&b);while(b!=flag){if(b==0){i=tree[i].lchild-1;}elsei=tree[i].rchild-1;if(tree[i].lchild==0)//找到叶节点,输出对应字符{printf("译码后对应的字符:%c\n",tree[i].ch);printf("译码后字符对应的权值:%f",tree[i].weight);i=m-1;}scanf("%d",&b);}if(tree[i].lchild!=0)printf("\n error\n"); }void main(){hufman( tree);creathufcode( code);decode( code, tree);}。

实验五哈夫曼树的建立、编码、解码

实验五哈夫曼树的建立、编码、解码

实验题目: 哈夫曼树的应用一、实验目的•加深理解哈夫曼树的定义和特性;•掌握哈夫曼树的存储结构与实现;•掌握哈夫曼树的应用二、实验内容•根据输入的权值信息建立哈夫曼树•输出各个叶子结点所表示字符的哈夫曼编码•对给定的密码串进行解码三、设计与编码1.基本思想2、编码#include<iostream.h>#include<string.h>const int MAX=20;struct huffnode{int weight;int lchild,rchild,parent;};struct huffinit //输入的权值信息的结构{char data;int weight;};struct huffcode //哈夫曼树编码的结构{char data;char code[MAX+1];};class HuffTree //哈夫曼树类的声明{ public:HuffTree(huffinit w[],int n);~HuffTree() { }void Select(int &min1,int &min2,int m);void Output(); //输出哈夫曼树最终状态(tree数组)void Encode(); //编码void Decode(char code[]); //解码private:huffnode tree[2*MAX-1]; //存储哈夫曼树huffcode cd[MAX]; //存储各个哈夫曼编码int size; //哈夫曼树的叶子结点数};HuffTree::HuffTree(huffinit w[],int n){size=n;for(int i=0;i<2*n-1;i++){tree[i].parent=-1;tree[i].lchild=-1;tree[i].rchild=-1;}for(i=0;i<n;i++){tree[i].weight=w[i].weight;cd[i].data=w[i].data;}int min1=-1;int min2=-1;int m=size;for(int k=n;k<2*n-1;k++){Select(min1,min2, m);tree[min1].parent=k;tree[min2].parent=k;tree[k].weight=tree[min1].weight+tree[min2].weight;tree[k].lchild=min1;tree[k].rchild=min2;m++;}}void HuffTree::Select(int &min1,int &min2,int m)//选择两个权值最小的结点{int a=100;int b=100;for(int i=0;i<m;i++){if(tree[i].weight<a&&tree[i].parent==-1){a=tree[i].weight;min1=i;}}for(i=0;i<m;i++){if(tree[i].weight<b&&tree[i].parent==-1&&i!=min1){b=tree[i].weight;min2=i;}}}void HuffTree::Output(){for(int i=0;i<2*size-1;i++){cout<<tree[i].weight<<" "<<tree[i].parent<<" "<<tree[i].lchild<<" "<<tree[i].rchild<<endl;}}void HuffTree::Encode() //编码{int m;int a;int j; char b[100]; int k;for(int i=0;i<size;i++){m=i;j=0;while(tree[m].parent!=-1){a=m;m=tree[m].parent;if(tree[m].lchild==a)b[j++]='0';elseb[j++]='1';}for(k=0,j=j-1;j>=0;j--)cd[i].code[k++]=b[j];cd[i].code[k]='\0';cout<<cd[i].data<<"--->"<<cd[i].code<<endl;;}}void HuffTree::Decode(char code[]) //解码{int a=2*size-2;//根节点的下标for(int i=0;i<n;i++){if(code[i]=='0'){a=tree[a].lchild;}if(code[i]=='1')a=tree[a].rchild;if(tree[a].lchild==-1&&tree[a].rchild==-1){cout<<cd[a].data;a=2*size-2;}elseif(code[i+1]=='\0')cout<<"error";}cout<<endl;}void main(){huffinit w[20];int n;char s[100];cout<<"请输入字符个数: ";cin>>n;for(int i=0;i<n;i++){cout<<"请输入第"<<i+1<<"个字符及权值: " ;cin>>w[i].data;cin>>w[i].weight;}HuffTree H(w,n);cout<<"已经建好的节点信息为"<<endl;H.Output();cout<<"已经建好的节点编码信息为"<<endl;H.Encode();char q;do{cout<<"请输入密码: ";cin>>s;cout<<endl;cout<<"还要继续解码吗?(Y/N)";cin>>q;}while(q=='Y');}四、调试与运行1.调试时遇到的主要问题及解决2.运行结果(输入及输出, 可以截取运行窗体的界面)五、实验心得。

哈夫曼编码与译码(附源码)

哈夫曼编码与译码(附源码)
#include<math.h>
#define max1 150
#define max2 50
#define max3 256
using namespace std;
class Htnote {
public:
char name; //字符名
}
}
sum--; input.close();
GetWeight(); //得到字符权值
}
};
class CodeNode//编码类
{
public:
if (letter[i].pname == ch) {
letter[i].num++;
sum++;
tag = 1;
}
cout << endl;
}
cout << "——————————————————————" << endl;
}
void InitHT()//哈夫曼初始化
{
L.ReadLetter();
}
c = f;
}
strcpy(Code[i].bits, &cd[start]); //将结果存入对应的编码数组中 }
}
void OutputHuffmanTCode() {
Name() {
num = 0;
lweight = 0;
}
};
class GetName {
public:
char namef[max2];
int n; //字符的种类

哈夫曼编码译码代码

哈夫曼编码译码代码

哈夫曼编码译码代码哈夫曼编码(Huffman Coding)是一种用于数据压缩的编码方法,通过对出现频率较高的字符使用较短的码字,对出现频率较低的字符使用较长的码字,从而实现数据的有效压缩。

以下是一个使用Java 实现哈夫曼编码和解码的示例代码:```javaimport java.util.ArrayList;import java.util.List;import java.util.PriorityQueue;public class HuffmanCoding {public static void main(String[] args) {String inputString = "This is a sample string";String encodedString = encode(inputString);String decodedString = decode(encodedString);System.out.println("Encoded String: " +encodedString);System.out.println("Decoded String: " + decodedString);}// 哈夫曼编码方法public static String encode(String inputString) {List<Character> characters = new ArrayList<>();List<Integer> frequencies = new ArrayList<>();for (char character : inputString.toCharArray()) {if (!characters.contains(character)) {characters.add(character);frequencies.add(1);} else {int index = characters.indexOf(character);frequencies.set(index, frequencies.get(index) + 1);}}// 创建最小堆,用于存储字符和频率PriorityQueue<CharacterFrequency> minHeap = new PriorityQueue<>();for (int i = 0; i < characters.size(); i++) {minHeap.add(new CharacterFrequency(characters.get(i), frequencies.get(i)));}// 构建哈夫曼树while (minHeap.size() > 1) {CharacterFrequency characterFrequency1 = minHeap.poll();CharacterFrequency characterFrequency2 = minHeap.poll();CharacterFrequency combinedCharacterFrequency = new CharacterFrequency(null,characterFrequency1.frequency + characterFrequency2.frequency);combinedCharacterFrequency.left = characterFrequency1;combinedCharacterFrequency.right = characterFrequency2;minHeap.add(combinedCharacterFrequency);}// 从根节点开始遍历哈夫曼树,生成编码StringBuilder encodedString = new StringBuilder();CharacterFrequency root = minHeap.poll();generateEncoding(root, encodedString);return encodedString.toString();}// 生成编码的辅助方法private static voidgenerateEncoding(CharacterFrequency characterFrequency, StringBuilder encodedString) {if (characterFrequency.left != null) {encodedString.append('0');generateEncoding(characterFrequency.left, encodedString);}if (characterFrequency.right != null) {encodedString.append('1');generateEncoding(characterFrequency.right, encodedString);}if (characterFrequency.character != null) {encodedString.append(characterFrequency.character);}}// 哈夫曼解码方法public static String decode(String encodedString) {List<Character> characters = new ArrayList<>();StringBuilder decodedString = new StringBuilder();int index = 0;while (index < encodedString.length()) {char c = encodedString.charAt(index);if (c == '0') {index++;CharacterFrequency characterFrequency = decodeNode(index, encodedString);characters.add(characterFrequency.character);} else if (c == '1') {index++;CharacterFrequency characterFrequency = decodeNode(index, encodedString);characters.add(characterFrequency.character);} else {characters.add(c);}}for (char character : characters.toCharArray()) {decodedString.append(character);}return decodedString.toString();}// 解码节点的辅助方法private static CharacterFrequency decodeNode(int index, String encodedString) {int numZeros = 0;while (encodedString.charAt(index) == '0') {numZeros++;index++;}int numOnes = 0;while (encodedString.charAt(index) == '1') {index++;}index--;CharacterFrequency characterFrequency = new CharacterFrequency(null,numZeros * numOnes);if (numZeros > 0) {characterFrequency.left = decodeNode(index - 1, encodedString);}if (numOnes > 0) {characterFrequency.right = decodeNode(index - 1, encodedString);}return characterFrequency;}// 字符频率类private static class CharacterFrequency {Character character;int frequency;CharacterFrequency left;CharacterFrequency right;public CharacterFrequency(Character character, int frequency) {this.character = character;this.frequency = frequency;}}// 字符频率比较器,用于构建最小堆private static class CharacterFrequencyComparator implements Comparator<CharacterFrequency> {@Overridepublic int compare(CharacterFrequencycharacterFrequency1, CharacterFrequency characterFrequency2) {return characterFrequency1.frequency - characterFrequency2.frequency;}}}```这段代码实现了哈夫曼编码和解码的功能。

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

测试文件内容Dear Editor: There is something to tell to you. I'm a middle school student.My name is Li Ming.Final exams are coming.Everyone is preparing for this.But there is some important problem during the review. Most of students often stay up late for the review.As the result,they always take a nap in the class and they can't keep the studying normal. I think we should be a reasonable time.The more relaxing we get,the better we will be.Brothers do not misuse wood workers I hope all the students can access to ideal scores. I'm expecting your answer and suggestion. Li Ming.源代码#include <stdio.h>#include <string.h>#include <stdlib.h>/* 哈夫曼树*/struct huffmantree{char ch; /* 字符*/int weight; /* 权值*/int parent; /* 父亲*/int lchild; /* 左孩子*/int rchild; /* 右孩子*/char *code; /* 编码*/};/* 字符-权值*/struct char_weight{char ch;int weight;};/* 带大小的字符-权值*/struct size_cw{int size;struct char_weight *cw;};/* 创建带大小的字符-权值表*/struct size_cw *create_scw(){FILE *fp;int i;int c;int cnt;int tmp[256]; /* 临时记录字符频度,哈希法*/struct size_cw *scw= (struct size_cw *)malloc(sizeof(struct size_cw));fp = fopen("data", "r");if (fp == NULL)return NULL; //执行错误for (i = 0; i < 256; i++)tmp[i] = 0;/* 从文件中统计字符频度*/while ((c = fgetc(fp)) != EOF)tmp[c]++;/* 统计字符种类*/scw->size = 0;for (i = 0; i < 256; i++)if (tmp[i] != 0)(scw->size)++;/* 根据tmp创建字符-权值表*/scw->cw = (struct char_weight *)malloc(sizeof(struct char_weight) *scw->size);cnt = 0;for (i = 0; i < 256; i++)if (tmp[i] != 0){scw->cw[cnt].ch = i;scw->cw[cnt].weight = tmp[i];cnt++;}fclose(fp);return scw; //执行成功}/* 在不存在父亲节点的节点中,找出1个权值最小的节点*/ int min_weight(struct huffmantree *ht, int n){int i;int min;for (i = 1; ; i++)if (ht[i].parent == 0){min = i;break;}for (i++; i <= n; i++){if (ht[i].parent)continue;if (ht[min].weight > ht[i].weight)min = i;}return min;}/* 在不存在父亲节点的点中,找出2个权值最小的节点*/ void min2_wieght(struct huffmantree *ht, int n, int *s1, int *s2) {*s1 = min_weight(ht, n);ht[*s1].parent = 1;*s2 = min_weight(ht, n);ht[*s1].parent = 0;}/* 创建哈夫曼树*/struct huffmantree *create_huffmantree(struct size_cw *scw) {int i;int s1, s2;struct huffmantree *ht;struct char_weight *cw = scw->cw;int leave = scw->size;int node = 2 * leave - 1;if (leave <= 1)return NULL;/* 0号节点不用*/ht = (struct huffmantree *)malloc(sizeof(struct huffmantree) *(node + 1));for (i = 1; i <= leave; i++, cw++){memset(ht+i, 0, sizeof(struct huffmantree));ht[i].ch = cw->ch;ht[i].weight = cw->weight;}for ( ; i <= node; i++)memset(ht+i, 0, sizeof(struct huffmantree));for (i = leave + 1; i <= node; i++){min2_wieght(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;}return ht;}/* 对哈夫曼树编码*/void code_huffmantree(struct huffmantree *ht, struct size_cw *scw) {int c, f;int i, start;int leave = scw->size;char *code = (char *)malloc(sizeof(char) * scw->size);code[leave-1] = '\0';for (i = 1; i <= leave; i++){start = leave - 1;for (c = i, f = ht[i].parent; f != 0; c = f, f = ht[f].parent)if (ht[f].lchild == c){code[--start] = '0';}else{code[--start] = '1';}ht[i].code = (char *)malloc(sizeof(char) * (leave - start));strcpy(ht[i].code, code + start);}free(code);}/* 打印字符频度表*/void print_cw(struct size_cw *scw){int i;for (i = 0; i < scw->size; i++)printf("%c\t %d\n", scw->cw[i].ch, scw->cw[i].weight);}/* 打印哈夫曼树*/void print_ht(struct huffmantree *ht, struct size_cw *scw){int i;for (i = 1; i <= 2*scw->size-1; i++)printf("%-5d%-5d%-5d\n", ht[i].parent, ht[i].lchild, ht[i].rchild); }/* 打印编码表*/void print_hc(struct huffmantree *ht, struct size_cw *scw){int i;for (i = 1; i <= scw->size; i++)printf("%c\t%s\n", ht[i].ch, ht[i].code);}/* 将编码保存到文件中*/int code_to_file(struct huffmantree *ht, struct size_cw *scw){FILE *fpr;FILE *fpw;char s[500];int c;int i;printf("请输入保存编码的文件名\n");gets(s);fpw = fopen(s, "w");if (fpw == NULL)return -1;fpr = fopen("data", "r");if (fpw == NULL)return -1;while ((c = fgetc(fpr)) != EOF)for (i = 1; i <= scw->size; i++)if (ht[i].ch == c){fprintf(fpw, "%s", ht[i].code);break;}fclose(fpw);fclose(fpr);return 0;}/* 从文件中读取编码,并绎码*/void from_file_decode(struct huffmantree *ht, struct size_cw *scw) {FILE *fp, *fpout;char s[1000], filename[500];int i, c;int leave = scw->size;printf("请输入要进行译码的文件名\n");gets(s);printf("请输入你要保存译码的文件名\n");gets(filename);printf("\n");printf("-------------------------------------------\n");printf("---------------译码结果如下----------------\n");printf(" \n");fp = fopen(s, "r");fpout = fopen(filename, "wt");while (1){i = 2 * leave - 1;while (ht[i].lchild){if ((c = fgetc(fp)) == EOF)return;if (c == '0'){i = ht[i].lchild;}else{i = ht[i].rchild;}}printf("%c", ht[i].ch);fputc(ht[i].ch, fpout);}printf("\n");fclose(fp);fclose(fpout);}//主函数int main(){struct size_cw *scw;;struct huffmantree *ht;scw = create_scw(); //统计字符频度及字符类型if (scw == NULL)return 1;printf("\n");printf("-----------------字符频度表-----------------\n");print_cw(scw); //打印字符频度表printf("\n");ht = create_huffmantree(scw); //哈夫曼树printf("------------------哈夫曼树------------------\n");print_ht(ht, scw);printf("\n");printf("--------------------编码表-------------------\n");code_huffmantree(ht, scw); //将编码存进文件print_hc(ht, scw); //打印编码表printf("\n");code_to_file(ht, scw);char s[1000];while (1){printf("输入'q'退出,输入其他进行解码\n");gets(s);if (s[0] == 'q')break;from_file_decode(ht, scw);printf(" \n");printf("-------------------------------------------\n");printf("\n");}printf("\n");return 0;}。

相关文档
最新文档