哈夫曼编码与译码
哈夫曼编码和译码
哈夫曼树的构造算法: 哈夫曼树的构造算法: 个结点的一维数组, (1)初始化哈夫曼树的 )初始化哈夫曼树的2n-1个结点的一维数组, 个结点的一维数组 即将各结点中的各个域均置0; 即将各结点中的各个域均置 ; 个权值存放到一维数组的前n个单元中 (2)读入 个权值存放到一维数组的前 个单元中, )读入n个权值存放到一维数组的前 个单元中, 它们即为初始森林中的n个只含根结点的权值 个只含根结点的权值; 它们即为初始森林中的 个只含根结点的权值; (3)对森林中的二叉树进行合并,产生 个新 )对森林中的二叉树进行合并,产生n-1个新 结点,依次存放到一维数组的第n+1个开始的单元中, 个开始的单元中, 结点,依次存放到一维数组的第 个开始的单元中 在这个过程中要注意对每个结点双亲域, 在这个过程中要注意对每个结点双亲域,左右孩子 域以及权值的修改. 域以及权值的修改.
13
s1=maxval;s2= maxval;/ 设maxval为float类型最大值 ; ;/*设 ;/ 为 类型最大值 */ for(j =1;j<=i;j+ +) ( ; ; ) if (ht[j].parent = =0) /*判断是否为根结点 判断是否为根结点*/ 判断是否为根结点 if (ht[j].weight<s1) { s2=s1;s1= ht[j].weight; p2=p1;p1=j; } ; ; ; ; else if (ht[j].weight <s2) { s2= ht[j].weight; p2=j; } ; ; ht[p1].parent=i;ht[p2].parent=i; ; ; ht[i].lchild =p1;ht[i].rchild=p2; ; ; ht[i].weight= ht[pl].weight+ht[p2].weight; ; } return (ht);} ;
哈夫曼编码和译码
哈夫曼编码和译码哈夫曼编码是一种用于数据压缩的编码方法,通过根据字符出现的频率对字符进行编码,以便能够用较少的位数来表示出现频率较高的字符。
编码过程中,根据频率最低的字符构建一棵哈夫曼树,将字符的编码表示为树的路径。
而哈夫曼译码则是将经过哈夫曼编码后的数据解码成原始数据的过程。
在给定的文本中,首先需要统计每个字符的出现频率。
然后使用这些频率构建哈夫曼树。
构建哈夫曼树的过程中使用最小堆数据结构,通过不断合并两个最小频率的字符节点来构建树。
合并两个节点的过程中,创建一个新的节点来作为它们的父节点,并将其频率设置为两个子节点频率之和。
在构建树的过程中,赋予左子节点编码为0,右子节点编码为1。
构建完成哈夫曼树后,将每个字符的编码表示为从根节点到该字符节点的路径,例如,向左走的路径可以表示为0,向右走的路径可以表示为1。
为了能够正确译码,需要将字符及其对应的编码存储在一个编码表中。
对于给定的文本数据,应用哈夫曼编码后,会得到一个压缩后的编码字符串。
在哈夫曼译码过程中,从根节点开始遍历编码字符串的每一位,如果是0,则向左子节点移动,如果是1,则向右子节点移动,直到到达叶子节点。
找到叶子节点后,将对应的字符输出,并回到根节点,继续下一位的译码,直到编码字符串结束。
哈夫曼编码可以实现无损压缩,即通过译码过程能够还原出原始数据,而不会丢失任何信息。
它是一种广泛应用于数据压缩领域的有效方法,用于减小数据存储和传输的大小。
在实际应用中,哈夫曼编码被广泛应用于图像、音频和视频等多媒体数据的压缩中。
总结起来,哈夫曼编码是一种用于数据压缩的编码方法,通过根据字符出现的频率对字符进行编码,以便用较少的位数来表示出现频率较高的字符。
哈夫曼译码则是将经过编码后的数据解码成原始数据的过程。
它通过构建哈夫曼树和编码表,实现了高效的数据压缩和解压缩。
哈夫曼编码被广泛应用于数据存储和传输领域,特别是在多媒体数据的压缩中。
哈夫曼编码与译码完整版
《数据结构》哈夫曼编码与译码实验报告题目:哈夫曼编码与译码班级:xxxx学号:xxxxxxxxxxx姓名:xxx完成时间:2012年12月19日一、程序总体结构主程序main显示系统时间showtime() 给用户提供选择方式chioce1()显示界面告诉用户程序名称show()打开文件进行加密openfile()退出程序输入电文进行加密input()将输入(文件中)的电文进行哈夫曼编码CrtHuffmanCode(ht,hc,n)统计输入(文件中)字母的出现频率CrW(data,w,count)【fcount(alldata,data,count)】输出每一个字母所对应的哈夫曼编码Printf(hc,n,data,alldata,count)将输入(文件中)的电文创建成哈夫曼树CrtHuffmantree(ht,w,n)对输入(文件中)的文字进行哈夫曼加密showall(hc,alldata,count,data,n)下面有几个不同的程序供选着参考:程序源代码:#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].rchil d<<"\t"<<endl;}outfile.close();cout<<"初始化结果已保存在hfmTree文件中\n";}void ToBeTree() //将正文写入文件ToBeTree中{ofstream outfile;outfile.open("ToBeTree.txt",ios::out);outfile<<"THIS PROGRAM IS MYFAVORITE";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')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;}{ int n;int Array[100];char cArray[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);}}源程序:#include<iostream>#include<fstream>#include<iomanip>#include<vector>using namespace std;typedef struct //节点结构{char data; //记录字符值long int weight; //记录字符权重unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树typedef char * *HuffmanCode; //动态分配数组存储哈夫曼编码表void Select(HuffmanTree &HT,int i,int &s1,int &s2) //在HT[1...t]中选择parent不为0且权值最小的两个结点,其序号分别为s1和s2{s1=0;s2=0;int n1=30000,n2=30000;for(int k=1;k<=i;k++){if(HT[k].parent==0){if(HT[k].weight<n1){n2=n1; n1=HT[k].weight;s2=s1; s1=k;}elseif(HT[k].weight<n2){n2=HT[k].weight;s2=k;}}}}void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int n)//将要编码的字符串存入空树中{ifstream fin1("zifu.txt");ifstream fin2("weight.txt");if(n<=1)return;int m=2*n-1;int i;HT=new HTNode[m+1];char *zifu;int *weight;zifu= new char[n+1];weight=new int[n+1];for(i=1;i<=n;i++)//将待编码的字符放在zifu数组中{char ch;ch=fin1.get();zifu[i]=ch;}for(i=1;i<=n;i++)//将带编码字符对应的权值放在weight数组中{fin2>>weight[i];}for( i=1;i<=n;i++){HT[i].data=zifu[i];HT[i].weight=weight[i];}for(i=n+1;i<=m;i++){HT[i].data='@';}for(i=1;i<=m;i++){HT[i].parent=HT[i].lchild=HT[i].rchild=0;}for(i=n+1;i<=m;++i){int s1,s2;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*));开辟一个求编码的工作空间char *cd;cd=(char *)malloc(n*sizeof(char));//开辟空间存放权值cd[n-1]='\0';for(i=1;i<=n;i++){int start=n-1;int c,f;for( c=i, f=HT[i].parent;f!=0;c=f,f=HT[f].parent)//从叶子到根逆向求编码{if(HT[f].lchild==c)cd[--start]='0';//若是左孩子编为'0'elsecd[--start]='1';//若是右孩子编为'1'}HC[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间strcpy(HC[i],&cd[start]);}delete []cd; //释放工作空间}void printHuffmanTree(HuffmanTree HT,int n) //显示有n个叶子结点的哈夫曼树的编码表{ ofstream fout("hfmtree.txt"); //将对应字符的的哈弗曼树存入cout<<"NUM"<<" "<<"data"<<" "<<"weight"<<" "<<"parent"<<" "<<"lchild"<<" "<<"rchlid"<<endl;for(int i=1;i<=2*n-1;i++){fout<<HT[i].weight<<setw(3)<<HT[i].parent<<setw(3)<<HT[i].lchild<<setw(3) <<HT[i].rchild<<endl;cout<<i<<setw(5)<<HT[i].data<<setw(3)<<HT[i].weight<<setw(3)<<HT[i].pare nt<<setw(3)<<HT[i].lchild<<setw(3)<<HT[i].rchild<<endl;}}void printHuffmanCoding(HuffmanTree HT,HuffmanCode HC,int n)//输出字符的对应哈弗曼编码并存入code.txt文件{cout<<"Huffman code is:"<<endl;ofstream fout("code.txt");for(int i=1;i<=n;i++){cout<<HT[i].data<<" --> ";cout<<(HC[i])<<endl;fout<<(HC[i])<<endl;}}void code_file(HuffmanTree HT,HuffmanCode HC,int n)//对文件tobetran.txt进行编码,并将编码存入codefile文件中{ifstream fin("tobetran.txt");ofstream fout("codefile.txt");vector<char> a;char ch;while((ch=fin.get())!='*')a.push_back(ch);cout<<"待编码的字符串为:";for(int k=0;k<a.size();k++)cout<<a[k];cout<<endl;cout<<"\n编码结果:"<<endl;for(int i=0;i<a.size();i++){for(int j=1;j<=n;j++){if(a[i]==HT[j].data){fout<<HC[j];break;}}}fin.close();fout.close();}void Decoding(HuffmanTree HT,HuffmanCode HC,int n)//打开codefile文件并对文件内容进行译码{int const m=2*n-1;ifstream fin("codefile.txt");ofstream fout("textfile.txt");vector<char> a;for(char c;fin>>c;)a.push_back(c);int count=0;for(int k=0;k<a.size();k++){cout<<a[k];count++;if(count%50==0)cout<<endl;}int i=0;int p; //用p来记住m的值cout<<endl;cout<<"\n译码结果:"<<endl;while(i<a.size()){p=m; //从哈弗曼数的根开始遍历while(HT[p].lchild){if(a[i]=='1')p=HT[p].rchild;elsep=HT[p].lchild;i++;}fout<<HT[p].data;cout<<HT[p].data;}}void main(){int n;cout<<"输入权值个数:"; //设置权值数值cin>>n;printf("\n");HuffmanTree HT; //哈夫曼树HTHuffmanCode HC; //哈夫曼编码表HCHuffmanCoding(HT,HC,n); //进行哈夫曼编码printHuffmanCoding(HT,HC,n); //显示编码的字符printf("\n");code_file(HT,HC,n); //显示要编码的字符串,并把编码值显示出来Decoding(HT,HC,n); //译码并显示译码后的字符串printf("\n\n\n");system("pause");}主要程序代码://HuffmanCode1.h#ifndef HUFFMAMCODE_H#define HUFFMAMCODE_H#include<iostream>#include<fstream>using namespace std;struct HuffmanNode //定义哈夫曼树各结点{int weight;int parent;int lchild,rchild;int flag;};class HuffmanCode1 //哈夫曼编码类{public:char Info[100];int Start;char Leaf;};class HuffmanTree1 //建立哈夫曼树类{private:HuffmanNode *Node;public:int f;HuffmanCode1 *hf;HuffmanTree1();~HuffmanTree1();void TranslatedCode();void CodeHuf(HuffmanNode a[],HuffmanCode1 b[],int n);void CreateHfmTree(char Str[],int m[],int n);void TransCode(HuffmanCode1 b[],int n) ;void TranslateArtcle(HuffmanCode1 b[],int n) ;};#endif //HUFFMAMCODE_HHuffmanCode.cpp#include "iostream"#include<stdio.h>#include "math.h"#include "stdlib.h"#include"HuffmanCode1.h"#include<string>using namespace std;#define MAXDA TA 10000 //最长字符串#define MAXSIZE 150 //最多子叶数//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////第一部分功能(W)实现的代码$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ HuffmanTree1::HuffmanTree1(){ Node=NULL; } //将树结点初始化为空HuffmanTree1::~HuffmanTree1(){ delete[] Node; } //释放结点空间void HuffmanTree1::CreateHfmTree(char Str[],int m[],int n)//建立哈夫曼树{int i,j,m1,m2,x1,x2;HuffmanNode *HfmNode=new HuffmanNode[2*n-1];HuffmanCode1 *HfmCode=new HuffmanCode1[n];for(i=0;i<2*n-1;i++){HfmNode[i].weight=0;HfmNode[i].parent=0;HfmNode[i].flag=0;HfmNode[i].lchild=-1;HfmNode[i].rchild=-1;}for(i=0;i<n;i++){HfmNode[i].weight=m[i];HfmCode[i].Leaf=Str[i];}for(i=0;i<n-1;i++){m1=m2=32767;x1=x2=0;for(j=0;j<n+i;j++){if(HfmNode[j].weight<=m1&&HfmNode[j].flag==0){m2=m1;x2=x1;m1=HfmNode[j].weight;x1=j;}else if(HfmNode[j].weight<=m2&&HfmNode[j].flag==0){m2=HfmNode[j].weight;x2=j;}}HfmNode[x1].parent=n+i;HfmNode[x2].parent=n+i;HfmNode[x1].flag=1;HfmNode[x2].flag=1;HfmNode[n+i].weight=HfmNode[x1].weight+HfmNode[x2].weight;HfmNode[n+i].lchild=x1;HfmNode[n+i].rchild=x2;}CodeHuf(HfmNode,HfmCode,n);TransCode(HfmCode,n);//TranslateArtcle(HfmCode,n);hf=HfmCode; f=n;}void HuffmanTree1::CodeHuf(HuffmanNode a[],HuffmanCode1 b[],int n) //对哈夫曼树进行编码{HuffmanCode1 Hfd;int c,p;for(int i=0;i<n;i++){Hfd.Start=n-1;c=i;p=a[c].parent;while(p!=0){if(a[p].lchild==c)[Hfd.Start]='0';else[Hfd.Start]='1';Hfd.Start--;c=p;p=a[c].parent;}printf("%c :",b[i].Leaf);for(int j=Hfd.Start+1;j<n;j++){b[i].Info[j]=[j];printf("%c",[j]);}printf("\n");b[i].Start=Hfd.Start;}}void HuffmanTree1::TransCode(HuffmanCode1 b[],int n) //对文章进行翻译并保存{ifstream ifs("WData.txt");ofstream ofs("WCode.txt");char s[1000];int t=0;char ch;cout<<"************************************************************** *****************"<<endl;printf("报文的编码为:\n");while(ifs.get(ch)){if(ch!='\n')s[t]=ch;for(int i=0;i<n;i++){if(s[t]==b[i].Leaf)for(int j=b[i].Start+1;j<n;j++){printf("%c",b[i].Info[j]);ofs<<b[i].Info[j];}}t++;}printf("\n");printf("报文的编码已经保存在WCode.txt中\n");cout<<"*********************************************************** ********************"<<endl;}void HuffmanTree1::TranslateArtcle(HuffmanCode1 b[],int n) //将所译的码翻译成文章并保存{int t=0;ifstream ifs("WCode.txt");ofstream ofs("TransWData.txt");string s;getline(ifs,s);for(t=0;s[t]!='\0';t++);int l=0;int j=0;printf("报文的译码结果为:\n");while(l<t){while(j<n){int hu=b[j].Start+1;int k=0;while(hu<n){if(s[l]==b[j].Info[hu]){l++;hu++;k++;}else{break;}}if(hu==n){printf("%c",b[j].Leaf);ofs<<b[j].Leaf;j=0;break;}else{l=l-k;j++; continue;}}}printf("\n");printf("译码的结果已经保存到TransWData.txt中\n");cout<<"*********************************************************** ********************"<<endl;}void HuffmanTree1::TranslatedCode(){ifstream ifs("WData.txt");char str[1000];char Str[100];int i=0,j,m[100],h,k=0;int n=0;cout<<"*********************************************************** ********************"<<endl;printf("文件中提取的文章字符串是:\n");char ch;while(ifs.get(ch)){printf("%c",ch);if(ch!='\n'){str[n++]=ch;}}printf("\n");printf("字符串中共含有字符%d个\n",n);for(i=0;i<n;i++){j=0;h=0;while(str[i]!=str[j])j++;if(j==i){Str[k]=str[i];printf("字符%c出现",Str[k]);}elsecontinue;for(j=i;j<n;j++){if(str[i]==str[j])h++;}printf("%d次\n",h);m[k]=h;k++;}cout<<"*********************************************************** ********************"<<endl;printf("字符串中字符种类有%d种\n",k);cout<<"*********************************************************** ********************"<<endl;printf("每个字符对应的哈夫曼编码是:\n");CreateHfmTree(Str,m,k);cin.get();// printf("\n");}//main.cpp//#include"HuffmanCode1.h"//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////第二部分功能实现的代码$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ typedef struct //哈弗曼树节点的结构体{char info; //关联字符信息unsigned int weight; //每个节点的权职unsigned int parent, lchild, rchild;}HTNode,*HuffmanTree;typedef char **HuffmanCode; //存储哈弗曼编码void Select(HuffmanTree HT, int j,int &s1,int &s2){ //选择双亲节点为0,并且最小的两个子叶节点int i=1,m;while(HT[i].parent!=0)i++; //找第一个双亲节点为0的子叶结点for(s2=s1=i;i<j;i++){ /保证s1中的权值最小,s2次小if(HT[i].parent==0 && HT[i].weight<HT[s1].weight){s2=s1;s1=i;}else if(HT[i].parent==0 && HT[i].weight>=HT[s1].weight &&HT[i].weight<=HT[s2].weight)s2=i;while(HT[i].parent==0 && s1==s2){m=i;m++;while(HT[m].parent!=0)m++;s2=m;}}}void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n, char *info){ //哈弗曼编码int i,m;HuffmanTree p;if(n<1) return;m = 2*n-1;HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode));for(p=HT+1,i=1;i<=n;++i,++p,++w,++info){ //初始化所有已存在的子叶信息p->info = *info;p->weight = *w;p->parent = 0;p->lchild = 0;p->rchild = 0;}//forfor(; i<=m;++i,++p){ //构造所需要的过度根节点p->weight = 0;p->parent = 0;p->lchild = 0;p->rchild = 0;}//forfor(i=n+1;i<=m;++i){ //建立哈弗曼树int s1,s2;Select(HT,i-1,s1,s2);HT[s1].parent =i;HT[s2].parent =i;HT[i].lchild = s2;HT[i].rchild = s1;HT[i].weight = HT[s1].weight+HT[s2].weight;}//for//哈弗曼编码HC = (HuffmanCode)malloc((n+1)*sizeof(char *));char* cd = (char*)malloc(n*sizeof(char));cd[n-1] = '\0';for(i=1;i<=n;++i){int f;unsigned int c;int 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';else cd[--start] = '1';}HC[i]=(char*)malloc((n-start)*sizeof(char));strcpy(HC[i], &cd[start]);}//forfree(cd);}//HuffmanCoding//Y功能实现输出并保存字符串的二进制编码void CheckCoding(HuffmanTree HT, HuffmanCode HC, char *strcheck, int m,int k) { ofstream ofs("BCode.txt"); //查询哈弗曼编码信息int p;for(int i=0; i<m; i++){for(int j=1; HT[j].info != strcheck[i]; j++);cout<<HC[j]; //输出并保存字符串的二进制编码ofs<<HC[j];}cout<<endl;cout<<"字符串的二进制编码已经保存在“BCode.txt”中"<<endl;//cout<<"译码翻译得到的文章已保存在“Data.txt”中"<<endl;cout<<"************************************************************** *****************"<<endl;cout<<"各字符对应的编码为:"<<endl; //输出各字符对应的哈夫曼编码for( p=1;p<=k;p++){cout<<HT[p].info <<": "<<HC[p]<<endl;}}//CheckCoding//对键盘输入的二进制代码进行译码void HuffmanTranslateCoding(HuffmanTree HT, int n,char*c){ ofstream ofs("TransBData.txt"); //译码过程int m=2*n-1;int i,j=0;cout<<"译码翻译得到的文章已保存在“TransBData.txt”中"<<endl;cout<<"译码翻译得到的文章为:";while(c[j]!='\0'){i=m;while(HT[i].lchild && HT[i].rchild){if(c[j]=='0')i=HT[i].lchild;else if(c[j]=='1')i=HT[i].rchild;j++;}cout<<HT[i].info; //翻译成字符串并输出和保存ofs<<HT[i].info;}}//译码过程、、对"BCode.txt"的编码进行译码void HuffmanTranslateCoding2(HuffmanTree HT, int n){ ifstream ifs("BCode.txt");ofstream ofs("TransBData2.txt");string c;int m=2*n-1;int i,j=0;getline(ifs,c);cout<<"译码翻译得到的文章已保存在“TransBData2.txt”中"<<endl;cout<<"译码翻译得到的文章为:";while(c[j]!='\0'){i=m;while(HT[i].lchild && HT[i].rchild){if(c[j]=='0')i=HT[i].lchild;else if(c[j]=='1')i=HT[i].rchild;j++;}cout<<HT[i].info; //翻译成字符串并输出和保存ofs<<HT[i].info;}}void Menushow(){cout<<"||******************************************************************** ****||"<<endl;cout<<" || HuffmanCode and HUffmanTranslate System ||"<<endl;cout<<" || ***********哈夫曼编码/译码系统************* ||"<<endl;cout<<" || *************欢迎使用本系统**************** ||"<<endl;cout<<" || 东北电力大学信息工程学院计机093班兴趣小组||"<<endl;cout<<" || 制作人:范辉强(组长)李哲周兴宇||"<<endl;cout<<"||******************************************************************** ****||"<<endl;cout<<" ||在本系统中您可以进行如下操作:||"<<endl;cout<<" ||第一部分功能:||"<<endl;cout<<" || A :从文件提取字符串,然后对提取的字符串进行编码||"<<endl;cout<<" || B :根据W操作对“WCode.txt”里的二进制编码进行译码||"<<endl;cout<<" ||第二部分功能:||"<<endl;cout<<" || C :对您输入的字符串进行编码||"<<endl;cout<<" || D:对BCode.txt里的编码进行译码||"<<endl;cout<<" || E :对您输入的二进制编码进行译码||"<<endl;cout<<" ||第三部分功能:||"<<endl;cout<<" || F :退出本系统||"<<endl;cout<<"||******************************************************************** ****||"<<endl;cout<<" ||温馨提示:||"<<endl;cout<<" || 执行A,请将您的数据存储在同目录下名为“WData”文本文档里||"<<endl;cout<<" || 在执行C操作时务必在您输入的字符串后加上“#”||"<<endl;cout<<" || B与A是对应的B在A后运行||"<<endl;cout<<" || D/E与C是对应的,即B/C是根据C来进行译码的||"<<endl;cout<<" || 译码D/E应在编码C后才能进行||"<<endl;cout<<" ||*********************** Copyright by FanFan ********************||"<<endl;}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///main().cppint main(){int n=0,i=0,k=0,j,h,*w;FILE *fp;char ch2,str[MAXDA TA],choose,name[]="BData.txt";w=new int[MAXSIZE];char *info;char *strcheck=str;info=new char[MAXSIZE];char *ch=new char[MAXSIZE];HuffmanTree HT=new HTNode[MAXSIZE];HuffmanCode HC=NULL;HuffmanTree1 HuffmanNode;Menushow();while(1){cout<<endl;cout<<"************************************************************** *****************"<<endl;cout<<"*********************************************************** ********************"<<endl;cout<<"请输入您要进行的操作(W/F/B/C/Y/T)(不区分大小写):"<<endl;cin>>choose;cout<<"************************************************************** *****************"<<endl;switch(choose){case 'A':case 'a':HuffmanNode.TranslatedCode();break;case 'B':case 'b':HuffmanNode.TranslateArtcle(HuffmanNode.hf,HuffmanNode.f);case 'D':case 'd':HuffmanTranslateCoding2( HT,n);break;case 'E':case 'e'://进行译码操作cout<<"请您输入您要编译的二进制编码: "<<endl;cin>>ch;HuffmanTranslateCoding(HT,n,ch);break;case 'T':case 't'://退出系统return 0;case 'C':case 'c'://进行编码操作cout<<"请输入您要编码的字符串:"<<endl;//从键盘输入字符串存放在字符数组str[1000]中/*if ((fp=fopen(name,"w"))==NULL){cout<<"cannot open file"<<endl;exit(0);}*/fp=fopen(name,"w");ch2=getchar();//接收上一次键盘输入的换行符ch2=getchar();while(ch2!='#'){fputc(ch2,fp);str[n++]=ch2;putchar(str[n-1]);ch2=getchar();}putchar(10);fclose(fp);cout<<endl;cout<<"输入的数据已经保存在“BData.txt”中"<<endl;cout<<"*******************************************************************************"<<endl;cout<<"字符串中共含有字符"<<n<<"个"<<endl;cout<<"*********************************************************** ********************"<<endl;for(i=0;i<n;i++) // 统计从键盘输入的字符串的信息{j=0;h=0;while(str[i]!=str[j])j++;if(j==i){info[k]=str[i];cout<<"字符"<<info[k]<<"出现";}elsecontinue;for(j=i;j<n;j++){if(str[i]==str[j])h++;}cout<<h<<"次"<<endl;w[k]=h;k++;}cout<<"************************************************************** *****************"<<endl;cout<<"字符串中字符种类有"<<k<<"种"<<endl;cout<<"************************************************************** *****************"<<endl;HuffmanCoding( HT, HC, w, n,info);//对输入的字符串进行编码*strcheck=str[0];cout<<"您输入的字符串编码为:"<<endl;CheckCoding(HT,HC,strcheck,n,k);break;default:cout<<"对不起,您的输入不正确!请重新输入"<<endl;}//switch}//while}//main程序清单.cpp#include<iostream>#include<stdio.h>#include<stdlib.h>#include<string>#include"Hh1.h"using namespace std;FILE * f1=fopen("d:\\pra1.txt","r");FILE * f2=fopen("d:\\pra2.txt","w");FILE * f3=fopen("d:\\pra4.huf","w");int main(){init(SN); //初始化字符数据库// input(f1); //读入初始文件的字符//for(int i=0;forest[i]!=NULL;i++)cout<<forest[i]->c<<":"<<forest[i]->weight<<endl; //输出字符及出现次数// cout<<"出现字符种类"<<count<<endl; //输出字符种类//HFM huffman(count); //创建哈夫曼树实例// huffman.creat(); //创建哈夫曼树// count=0;huffman.hufcode(); //哈夫曼编码,此时为逆向//exchange(); //调整首尾对调哈夫曼编码// huffman.savewithhufcode(f1,f2); //用哈夫曼编码存储原文件//cout<<endl;cout<<"1.查看哈夫曼编码"<<endl;cout<<"2.哈夫曼解码"<<endl;cout<<"3.查看压缩率"<<endl;int choice;cin>>choice;while(choice>=1&&choice<=3){switch(choice){case 1:{for(i=0;hufNode[i].sig!=NULL;i++){cout<<"字符"<<hufNode[i].sig->c<<"的哈夫曼编码:"; //输出哈夫曼编码//for(int j=0;j<hufNode[i].size;j++)cout<<hufNode[i].code[j];cout<<endl;}cout<<"最大列数:"<<huffman.maxc()<<endl;break;}case 2:{fclose(f2);f2=fopen("d:\\pra2.txt","r");huffman.hufdecode(f2,f3); //哈夫曼解码//cout<<endl;break;}case 3:{compress(); //查看压缩情况//cout<<endl;}}cout<<"1.查看哈夫曼编码"<<endl;cout<<"2.哈夫曼解码"<<endl;cout<<"3.查看压缩率"<<endl;cin>>choice;}cout<<"*谢谢使用*"<<endl; //退出操作//return 0;}.h#include<iostream>using namespace std;struct signode{ //signode节点,哈夫曼树节点//char c; //字符//int weight; //权重//bool b; //文章中是否出现//。
哈夫曼编码和译码
哈夫曼编码和译码哈夫曼编码和译码是一种常用的数据压缩算法,它通过将出现频率较高的字符用较短的编码表示,从而减小数据的存储空间。
本文将介绍哈夫曼编码和译码的原理和应用。
哈夫曼编码是由美国数学家大卫·哈夫曼于1952年提出的一种编码方法。
它的基本思想是根据字符出现的频率来构建一棵二叉树,出现频率较高的字符位于树的较低层,而出现频率较低的字符位于树的较高层。
通过这种方式,出现频率较高的字符可以用较短的编码表示,而出现频率较低的字符则用较长的编码表示。
具体来说,哈夫曼编码的过程如下:首先,统计待编码的字符出现的频率,并根据频率构建一个字符频率表。
然后,根据字符频率表构建哈夫曼树,其中每个字符对应一个叶子节点,而非叶子节点的权值为其子节点权值之和。
接下来,通过遍历哈夫曼树,给每个字符赋予对应的编码,其中左子树路径上的编码为0,右子树路径上的编码为1。
最后,将编码后的字符序列存储起来,即完成了哈夫曼编码的过程。
哈夫曼译码是哈夫曼编码的逆过程,它通过已知的哈夫曼编码和字符频率表来将编码还原为原始的字符序列。
具体来说,哈夫曼译码的过程如下:首先,根据已知的字符频率表构建哈夫曼树。
然后,从根节点开始,根据编码的0和1进行遍历,直到叶子节点。
每次遍历到叶子节点时,将对应的字符输出,并重新回到根节点,继续下一次遍历,直到所有的编码都被译码为字符。
哈夫曼编码和译码在数据压缩领域有着广泛的应用。
由于哈夫曼编码可以将出现频率较高的字符用较短的编码表示,从而减小了数据的存储空间。
在传输大量文本、图像、音频等数据时,可以使用哈夫曼编码将数据进行压缩,从而减少传输的时间和带宽消耗。
而哈夫曼译码则可以将压缩后的数据还原为原始的数据,保证了数据的完整性和准确性。
除了数据压缩,哈夫曼编码和译码还有其他的应用。
在通信领域,哈夫曼编码可以用于错误检测和纠正,通过添加冗余信息来检测和纠正传输过程中的错误。
在图像和音频处理领域,哈夫曼编码可以用于图像和音频的压缩和解压缩,从而减小存储空间和提高传输效率。
基于哈夫曼编码的编码译码问题
基于哈夫曼编码的编码译码问题基于哈夫曼编码的编码译码问题相关问题:1.哈夫曼编码是什么?如何进行编码和译码?2.哈夫曼编码的原理是什么?3.哈夫曼编码的应用领域有哪些?4.如何生成哈夫曼编码树?5.哈夫曼编码的时间复杂度是多少?6.哈夫曼树的构建方法有哪些?7.哈夫曼编码在数据压缩中的作用是什么?8.哈夫曼编码存在的局限性是什么?9.哈夫曼编码与其他编码方法的比较有哪些特点?10.如何解决哈夫曼编码中的冲突问题?解释说明:1.哈夫曼编码是一种基于字符频率的可变长度编码方法。
它通过将出现频率高的字符用较短的编码来表示,出现频率低的字符用较长的编码来表示,以达到数据压缩的目的。
编码过程中,首先统计字符出现频率,然后构建哈夫曼树,根据树的结构生成编码表,最后对原始数据进行编码。
译码过程中,根据生成的编码表和编码数据,逐位解码还原原始数据。
2.哈夫曼编码的原理是基于贪心算法,通过构建哈夫曼树,将出现频率高的字符放在树的上层,出现频率低的字符放在树的下层,以实现最优的编码效果。
在编码过程中,使用了前缀码的特性,即任何一个编码不能是另一个编码的前缀,从而保证了译码的唯一性。
3.哈夫曼编码广泛应用于数据压缩领域,可以对文本、图像、音频等数据进行压缩和解压缩。
此外,哈夫曼编码也用于数据传输中的差错检测和纠正,以及编码理论的研究等领域。
4.生成哈夫曼编码树的方法主要有两种:静态生成和动态生成。
静态生成是根据给定的字符频率进行构建,而动态生成是根据实际数据的字符频率进行构建。
5.哈夫曼编码的时间复杂度为O(nlogn),其中n为字符的个数。
这是由于在构建哈夫曼树时需要进行n-1次合并操作,每次合并的时间复杂度为O(logn)。
6.哈夫曼树的构建方法主要有两种:霍夫曼算法和优先队列算法。
霍夫曼算法是经典的构建方法,通过反复选择权值最小的两个节点合并构建树,直到所有节点合并为一棵树。
优先队列算法则先将节点插入优先队列中,每次取权值最小的两个节点合并。
哈夫曼编码译码代码
哈夫曼编码译码代码哈夫曼编码(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.设计目的:通过对简单哈夫曼编/译码系统的设计与实现来熟练掌握树型结构在实际问题中的应用。
2.问题的描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码。
系统应该具有如下的几个功能:接收原始数据、编码、译码、打印编码规则。
二、数据结构的设计:1.哈夫曼结点结构体:typedef struct HtNode{int weight;int parent, lchild, rchild;}HtNode;2.哈夫曼树结构体:typedef struct HtTree{struct HtNode ht[MAXNODE+1];int root;}HtTree, *PHtTree;三、功能(函数)设计:总体上划分为四个模块,具体功能描述如下:1.初始化功能模块:接收输入信息,并正确输出2.建立哈夫曼树的功能模块:按照构造哈夫曼树的算法构造哈夫曼树,将HuffNode数组中的各个位置的各个域都添上相关的值3.哈夫曼编码的功能模块:根据输入的相关字符信息进行哈夫曼编码,然后将结果存入,同时将字符与0、1代码串的一一对应关系打印到屏幕上。
4.译码的功能模块:接收需要译码的0、1代码串,按照哈夫曼编码规则将其翻译成字符集中的字符所组成的字符串形式,将翻译的结果在屏幕上输出四、界面设计:该界面操做简单,内容详细,便于程序使用者根据提示轻松上手。
简洁明朗是该界面最大的特点。
哈夫曼编/译码请逐个输入结点和结点的权值>>>按Enter键开始根据此提示界面进入程序使用阶段。
请输入结点个数:根据用户输入结点个数,动态输入并存储字符及权值然后输出字符与0、1代码串的对应关系。
进入以下界面,进行后续操作1----------------------------编码2----------------------------译码3----------------------------重新输入权值;0----------------------------退出用户键入“0”,即可出编码译码操作五、程序设计:1.函数功能说明及其程序流程图的描述:1>:main函数:控制整个程序的整个流程。
哈夫曼编码译码器实验报告
哈夫曼编码译码器实验报告实验名称:哈夫曼编码译码器实验一、实验目的:1.了解哈夫曼编码的原理和应用。
2.实现一个哈夫曼编码的编码和译码器。
3.掌握哈夫曼编码的编码和译码过程。
二、实验原理:哈夫曼编码是一种常用的可变长度编码,用于将字符映射到二进制编码。
根据字符出现的频率,建立一个哈夫曼树,出现频率高的字符编码短,出现频率低的字符编码长。
编码过程中,根据已建立的哈夫曼树,将字符替换为对应的二进制编码。
译码过程中,根据已建立的哈夫曼树,将二进制编码替换为对应的字符。
三、实验步骤:1.构建一个哈夫曼树,根据字符出现的频率排序。
频率高的字符在左子树,频率低的字符在右子树。
2.根据建立的哈夫曼树,生成字符对应的编码表,包括字符和对应的二进制编码。
3.输入一个字符串,根据编码表将字符串编码为二进制序列。
4.输入一个二进制序列,根据编码表将二进制序列译码为字符串。
5.比较编码前后字符串的内容,确保译码正确性。
四、实验结果:1.构建哈夫曼树:-字符出现频率:A(2),B(5),C(1),D(3),E(1) -构建的哈夫曼树如下:12/\/\69/\/\3345/\/\/\/\ABCDE2.生成编码表:-A:00-B:01-C:100-D:101-E:1103.编码过程:4.译码过程:5.比较编码前后字符串的内容,结果正确。
五、实验总结:通过本次实验,我了解了哈夫曼编码的原理和应用,并且实现了一个简单的哈夫曼编码的编码和译码器。
在实验过程中,我充分运用了数据结构中的树的知识,构建了一个哈夫曼树,并生成了编码表。
通过编码和译码过程,我进一步巩固了对树的遍历和节点查找的理解。
实验结果表明,本次哈夫曼编码的编码和译码过程正确无误。
在实验的过程中,我发现哈夫曼编码对于频率较高的字符具有较短的编码,从而实现了对字符串的高效压缩。
同时,哈夫曼编码还可以应用于数据传输和存储中,提高数据的传输效率和存储空间的利用率。
通过本次实验,我不仅掌握了哈夫曼编码的编码和译码过程,还深入了解了其实现原理和应用场景,加深了对数据结构和算法的理解和应用能力。
根据哈夫曼编码译码
根据哈夫曼编码译码
哈夫曼编码是一种用于数据压缩的编码方法,它通过将频率较
高的字符用较短的编码表示,而频率较低的字符用较长的编码表示,从而实现对数据的压缩。
译码即是将经过哈夫曼编码压缩的数据解
码还原为原始数据。
要进行哈夫曼编码的译码,需要先构建哈夫曼树,然后根据哈
夫曼树进行译码操作。
下面是一种常见的哈夫曼编码译码的步骤:
1. 构建哈夫曼树:
统计待译码的数据中每个字符出现的频率。
根据字符频率构建哈夫曼树,频率越高的字符离根节点越近。
2. 译码操作:
从根节点开始,按照编码依次遍历哈夫曼树。
如果遇到编码为0的路径,就向左子树移动;如果遇到编码
为1的路径,就向右子树移动。
当遍历到叶子节点时,就找到了对应的字符,输出该字符,
并回到根节点继续遍历。
通过以上步骤,就可以将经过哈夫曼编码压缩的数据进行译码,还原为原始数据。
需要注意的是,译码过程中要根据编码的长度进行判断,以避
免出现歧义。
如果编码长度不一致或者无法匹配到叶子节点,就需
要检查哈夫曼编码的构建是否正确。
总结起来,哈夫曼编码的译码过程包括构建哈夫曼树和根据编
码进行遍历的操作。
通过正确的译码操作,可以将经过哈夫曼编码
压缩的数据还原为原始数据。
简述哈夫曼编码译码过程
简述哈夫曼编码译码过程哈夫曼编码是一种用于数据压缩的无损编码方法,它基于字符出现频率的统计信息,将频率较高的字符用较短的二进制编码表示,而将频率较低的字符用较长的二进制编码表示。
在对数据进行解码时,需要使用相同的编码表来将编码转换回原始数据。
哈夫曼编码的过程可以分为两个主要步骤:构建哈夫曼树和生成编码表。
下面将详细介绍每个步骤的实现过程。
构建哈夫曼树:1. 统计字符的频率:遍历要编码的数据,统计每个字符出现的频率。
2. 创建叶节点列表:将每个字符及其频率作为一个叶节点,构建一个列表。
3. 构建哈夫曼树:重复执行以下操作,直到只剩下一个节点:a. 从叶节点列表中选择两个频率最低的节点作为左右子节点。
b. 创建一个新的节点,其频率为左右子节点频率之和,并将其设为左右子节点的父节点。
c. 将新的父节点添加到叶节点列表中。
d. 从叶节点列表中删除选择的两个节点。
4. 哈夫曼树的根节点即为构建完成的树。
生成编码表:1. 遍历哈夫曼树:从根节点开始,遍历哈夫曼树的每个节点。
a. 若当前节点为叶节点,记录该节点所表示字符的编码路径。
b. 若当前节点有左子节点,将路径标记为0,并继续遍历左子节点。
c. 若当前节点有右子节点,将路径标记为1,并继续遍历右子节点。
2. 将每个字符与其对应的编码路径关系保存在编码表中。
哈夫曼编码的过程中,编码表的生成是非常重要的一步。
通过遍历哈夫曼树,可以确定每个字符的唯一编码,从而在进行译码时能够将编码路径按照对应的编码表转换为原始数据。
译码过程:1. 读取编码数据:将压缩后的二进制数据按位读取。
2. 解码树的遍历:从哈夫曼树的根节点开始,按照读取的二进制位(0或1)依次向左或向右遍历。
3. 判断节点类型:若当前节点为叶节点,表示已找到对应的字符,记录该字符并重新从根节点开始遍历。
4. 判断读取结束:若读取的二进制数据已经全部解码完毕,则译码结束;否则继续读取下一位二进制数据进行遍历。
数据结构 哈夫曼编码与译码
数据结构哈夫曼编码与译码哈夫曼编码与译码是数据结构中的重要概念,它是一种可变长度编码的方法,用于压缩数据。
在本文中,我将详细介绍哈夫曼编码与译码的原理、步骤以及应用。
一、哈夫曼编码的原理哈夫曼编码是一种根据字符出现的频率来构建编码表的方法,使得频率较高的字符使用较短的编码,频率较低的字符使用较长的编码。
这样可以有效地减少数据的存储空间。
二、哈夫曼编码的步骤1. 统计字符频率:遍历待编码的文本,统计每个字符出现的频率。
2. 构建哈夫曼树:根据字符频率构建哈夫曼树。
首先将每个字符作为一个独立的树节点,然后合并频率最低的两个节点,生成一个新的节点,频率为这两个节点的频率之和。
重复此过程,直到所有节点都合并为一个根节点,得到哈夫曼树。
3. 生成编码表:从根节点开始遍历哈夫曼树,左子树路径为0,右子树路径为1,将路径上的0和1依次添加到对应字符的编码中,得到编码表。
4. 进行编码:根据编码表,将待编码的文本中的每个字符替换为对应的编码。
5. 完成编码:得到编码后的文本。
三、哈夫曼译码的步骤1. 根据编码表,将编码后的文本逐个字符地进行译码。
从根节点开始,根据字符是0还是1,选择左子树或右子树进行下一步操作。
2. 如果到达叶子节点,则找到对应的字符,并将该字符添加到译码结果中。
3. 重复上述步骤,直到译码结束,得到原始文本。
四、哈夫曼编码与译码的应用哈夫曼编码与译码广泛应用于数据压缩领域。
通过使用哈夫曼编码,可以大大减小数据的存储空间,提高数据传输的效率。
在图像、音频、视频等大数据文件的传输和存储中,哈夫曼编码被广泛使用。
总结:哈夫曼编码与译码是一种基于字符频率的编码方法,可以有效地压缩数据。
通过统计字符频率、构建哈夫曼树、生成编码表等步骤,可以实现对数据的编码和译码。
哈夫曼编码在数据压缩领域有着广泛的应用,可以大大减小数据的存储空间,提高数据传输的效率。
哈夫曼编码译码
哈夫曼编码译码哈夫曼编码译码编码与译码是信息传输的两个基本环节,哈夫曼编码是一种基于数据压缩的编码方式,能够有效减小数据传输时所需的带宽和存储空间,广泛应用于图像、音频、视频等大数据的传输和存储中。
本文将从哈夫曼编码的定义、算法及其应用等三个方面进行探讨。
一、哈夫曼编码的定义哈夫曼编码,又称为变长编码或最优编码,是一种通过树形结构来实现数据压缩的编码方式。
其算法的基本思想是:对于频率高的字符,分配较短的编码;对于频率低的字符,分配较长的编码。
这样,可以减小数据传输时所需要的带宽和存储空间。
二、哈夫曼编码的算法哈夫曼编码的算法分为两个步骤:建立哈夫曼树和生成编码。
1. 建立哈夫曼树:首先将每个字符看作独立的一个节点,然后根据字符出现的频率来构建哈夫曼树。
具体的方法是:对于给定的一组字符,计算其出现的频率,并将其按照频率的大小进行排序。
然后将频率最小的两个字符合并为一个节点,该节点的频率为两个字符的频率之和,并将该节点插入到集合中。
重复此过程,直到集合中只剩下一个节点,即构建出了哈夫曼树。
2. 生成编码:从根节点开始,遍历树的所有节点(左子树编码为0,右子树编码为1),并记录所有节点对应的字符编码。
这样,每个字符就可以表示为一串01序列,其中该序列的长度越小,表示该字符在原数据中出现的频率越高。
三、哈夫曼编码的应用哈夫曼编码在数据压缩、网络传输、存储优化等领域都有广泛的应用。
1. 数据压缩:哈夫曼编码可将文件的体积减小到原来的三分之一左右,从而有效地减小文件的传输和存储所需要的空间。
2. 网络传输:在网络传输中,带宽和传输速率是非常宝贵的资源。
哈夫曼编码可以将传输的数据压缩到最小,从而减小网络传输的时间和成本。
3. 存储优化:在资源有限的设备上,如手机、PDA等,存储空间通常是一个非常重要的考虑因素。
使用哈夫曼编码技术,可以减小存储所需的空间,从而为设备的其他功能留出更多的空间。
总之,哈夫曼编码是一种非常重要的编码方式,广泛被应用于数据传输和存储中。
数据结构哈夫曼编码译码c语言
数据结构哈夫曼编码译码c语言哈夫曼编码是一种经典的数据压缩算法。
这种算法可以根据数据中出现频率最高的字符生成一个种类较少的编码表,然后用这个编码表来对数据进行编码,从而达到压缩数据的效果。
哈夫曼编码的核心是生成编码表,生成编码表的过程包括以下几个步骤:1. 统计字符出现频率。
遍历一遍数据,统计每个字符出现的次数。
2. 创建哈夫曼树。
将每个字符出现的次数作为权值,构造一棵哈夫曼树。
构造哈夫曼树需要用到一种优先队列。
3. 生成编码表。
对哈夫曼树进行遍历,当遇到一个叶子节点时,将它的路径上的所有节点转换成一个编码,这个编码就是该节点代表的字符的哈夫曼编码。
4. 对数据进行编码。
按照编码表,将原始数据中的每个字符都替换成对应的哈夫曼编码,得到压缩数据。
哈夫曼编码的解码操作相对简单,只需要根据编码表将每个哈夫曼编码转换成它代表的字符,再将这些字符拼接起来就可以得到原始数据。
以下是C语言实现哈夫曼编码和译码的例子:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX_NODE 100typedef struct node {char data;int freq;int parent, lchild, rchild;} Node;int nodes_num;Node* nodes;void build_huffman_tree() {int i, j, min1, min2;for (i = 0; i < nodes_num - 1; i++) {min1 = min2 = -1;for (j = 0; j < nodes_num + i; j++) {if (nodes[j].parent == -1) {if (min1 == -1 || nodes[j].freq < nodes[min1].freq) {min2 = min1;min1 = j;} else if (min2 == -1 || nodes[j].freq < nodes[min2].freq) { min2 = j;}}}nodes[min1].parent = nodes_num + i;nodes[min2].parent = nodes_num + i;nodes[nodes_num + i].lchild = min1;nodes[nodes_num + i].rchild = min2;nodes[nodes_num + i].freq = nodes[min1].freq + nodes[min2].freq;}}nodes_num = 0;nodes = (Node*)malloc(MAX_NODE * sizeof(Node));for (i = 0; i < MAX_NODE; i++) {nodes[i].freq = nodes[i].parent = -1;nodes[i].lchild = nodes[i].rchild = -1;}build_huffman_tree();codes_num = 0;codes = (Code*)malloc(nodes_num * sizeof(Code));printf("src: %s\n", src);return 0;}```上述代码中,我们使用结构体来表示哈夫曼树的节点,其中包括该节点的权值(即字符出现的次数)、父节点、左右孩子节点等信息。
哈夫曼编码与译码
一、设计思想程序要求:利用哈夫曼树对字符串进行编码,要求每个字符有自己唯一的编码。
将得到的一串字串译成0、1编码后存到一个文件夹中,然后再从这个文件夹中读出这串编码进行解码。
实现方法:输入一串字符,要求字符的区间为大写的26个英文字母,将获得的串字符用计算权值的函数(jsquanzhi())进行字符统计,统计出现的字符种数以及每种字符出现的次数,将该种字符出现的次数作为它的权值。
将出现的字符的权值和该字符依次分别赋给两个结构体HT和HC,利用HT(节点)权值的大小建立哈夫曼树,首先用选择函数select()函数选择两个权值最小的字符作为叶子节点,创建一个新的节点作为这两个叶节点的父节点,被选中的节点给他的HT[i].parent赋值是他下次不再被选中,父节点的权值为,子节点的权值之和。
然后将该将父节点放入筛选区中,再进行选择(被选过的不再被使用),直到所有的节点都被使用,这样一个哈夫曼树就被建立了。
根据每个字符在哈夫曼书中的位置来编译每个字符的0、1密文代码,从叶节点判断该叶节点是其父节点的左右字左字为‘0’,右子为‘1’,在判断父节点是上级父节点的左右子直至根节点,将生成的0、1字符串按所表示的字符倒序存入HC相应的字符的bins[]数组。
重新一个一个字符的读取输入的字符串,按照字符出现的顺序将它转为0、1代码并存到一个txt文件夹中去。
解码时从文件夹中,一个一个字符的读出那串0、1代码赋给一个临时字符串cd[],用该字符串与每个字符的HC[i].bins密文比较,直到与一个字符的密文相同时,译出该字符,将字符存放在临时字符数组tempstr[]中,清空临时字符串继续读取0、1代码进行翻译,直至文件密文结束为止。
于是就得到了原先被加密的那串字符串。
二、算法流程图三、源代码// hafuman.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"#include "stdlib.h"#include "string.h"#include "stdio.h"#define n 100 //叶节点的个数小等于n#define m 2*n-1 //总结点的个数为m=2*n-1int num; //定义一个全局变量用于存放字符种类个数typedef struct //结构体用于存放树节点包括节点的父节点、左子、右子以及权值{ int weight;int parent,lchild,rchild;}HTNode;typedef HTNode HafumanTree[m+1]; //重命名HTNodetypedef struct //结构体由于存放每个字符的密文和长度{char ch;char bits[10];int len;}CodeNode;typedef CodeNode HafumanCode[n+1]; //重命名CodeNodeint _tmain(int argc, _TCHAR* argv[]){int quan[27]; //声明一个数组用以存放26字符的权值char getstr[300],str[27];//声明两个字符串数组一个用于存输入一个由于存放输入中含有的字符char *s; //声明一个char型指针用于指向字符HafumanTree HT; //声明m+1个树节点HafumanCode HC; //声明n+1个codeint jisuanquan(char *s,int quan[],char str[]); //声明需要调用的函数void gjhafumantree(HafumanTree HT,HafumanCode HC,int quan[],char str[]);void Hafumanencode(HafumanTree HT,HafumanCode HC);void coding(HafumanCode HC,char *str);char *decode(HafumanCode HC);printf("请输入要加密的字符串:\n");gets(getstr); //获得输入的字符串num=jisuanquan(getstr,quan,str); //统计字符串中含有字符种类个数//printf("%d\n",num);gjhafumantree(HT,HC,quan,str); //根据字符权值构建哈夫曼树Hafumanencode(HT,HC); //根据哈夫曼树确定每个字符的code coding(HC,getstr); //将字符串译码存入文件夹s=decode(HC); //将暗文解码printf("解密为:\n");printf("%s\n",s);system("pause");return 0;}//函数int jisuanquan(char *s,int quan[],char str[]) //计算字符串中字符权值{char *p;int i,j,k,quantemp[27];for(i=1;i<27;i++) //将所有字符的权值赋成0 {quantemp[i]=0;}for(p=s;*p!='\0';p++) //判断字符串是否结束{if(*p>='A'&&*p<='Z') //判断字符是否为26字母{k=*p-64; //看是26个字符中的哪个字符quantemp[k]++; //字符权值加1}}j=0;for(i=1,j=0;i<27;i++){if(quantemp[i]!=0){j++; //用于统计字符种类个数str[j]=i+64; //str按字母表顺序存储出现过的字符quan[j]=quantemp[i];}}return j;}void select(HafumanTree HT,int k,int *s1,int*s2) //选择权值最小的两个{int i,j;int min1=9999; //声明一个int类型的数值min1,赋个较大的输给它for(i=1;i<=k;i++) //选择权值最小的一个节点(且该节点无父节点){if((HT[i].weight<min1)&&(HT[i].parent==0)){j=i;min1=HT[i].weight;}}*s1=j;min1=9999;for(i=1;i<=k;i++){if((HT[i].weight<min1)&&(HT[i].parent==0)&&(i!=*s1))//选择权值最小的一个节点(且该节点无父节点){j=i;min1=HT[i].weight;}}*s2=j;}void gjhafumantree(HafumanTree HT,HafumanCode HC,int quan[],char str[]) //构建哈夫曼树{int i,s1,s2;for(i=1;i<2*num-1;i++) //将所有的节点赋空{HT[i].lchild=0;HT[i].rchild=0;HT[i].parent=0;HT[i].weight=0;}for(i=1;i<=num;i++) //将num个字符的权值赋给num叶节点{HT[i].weight=quan[i];}for(i=1;i<=num;i++) //将num个字符赋给codenode{HC[i].ch=str[i];}i=1;while(i<=num){ printf("===%c===%d===\n",HC[i].ch,quan[i]);i++;} //输出每个字符的及其权值for(i=num+1;i<=2*num-1;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 Hafumanencode(HafumanTree HT,HafumanCode HC){int c,p,i;char cd[n]; //临时数组用于记录字符在哈夫曼树的位置int start;cd[num]='\0'; //给cd赋个结束符for(i=1;i<=num;i++){start=num;c=i;while((p=HT[c].parent)>0) //根据节点是其父节点的左右子来记录它的位置{cd[--start]=(HT[p].lchild==c)?'0':'1';c=p; //将父节点转为子节点}strcpy(HC[i].bits,&cd[start]); //将得到的0、1字串存入结构体HCprintf("%c:%s\n",HC[i].ch,HC[i].bits);HC[i].len=num-start; //求每个字符0、1编码长度}}void coding(HafumanCode HC,char *str) //根据哈夫曼树确定每个字符的0、1代码code{int i,j;FILE *fp; //声明一个文件夹指针fp=fopen("codefile.txt","w"); //打开文件夹codefileprintf("密文为:\n");while(*str) //字符串未结束时{for(i=1;i<=num;i++){if(HC[i].ch==*str) //判断字符是否在Codenode中存在{for(j=0;j<HC[i].len;j++) //将codenode中该字符的1、0代码存入文件夹{fputc(HC[i].bits[j],fp);}printf("%s",HC[i].bits);break;}}str++; //字符后移}printf("\n");fclose(fp);}char *decode(HafumanCode HC){FILE *fp;char tempstr[9999];char *p;static char cd[n+1]; //char型数组用于存放从文件夹中读取的1、0代码int i,j,k=0,jsjs;fp=fopen("codefile.txt","r");while(!feof(fp)) //当文件夹读取没有结束{jsjs=0; //判读一个字符是否译码结束for(i=0;(i<num)&&(jsjs==0)&&(!feof(fp));i++) //当一个字符未译完并且文件未读取结束{ cd[i]=' ';cd[i+1]='\0'; //让cd[]赋成空格cd[i]=fgetc(fp); //读取文件夹中的一个字符for(j=1;j<=num;j++){f(strcmp(HC[j].bits,cd)==0) //看cd[]的字符串是否等于Codenode中的某个密文{tempstr[k]=HC[j].ch;jsjs=1;printf("=%s=",HC[j].bits);k++;break;}//将译出的字符赋给临时字符串tempstr[],标记一个字符译码结束jsjs赋1,跳出循环}}}tempstr[k]='\0'; //赋给临时字符串一个结束标志p=tempstr; //char型指针指向临时字符串return p;}四、运行结果图5 哈夫曼编码与译码运行结果图五、遇到的问题及解决这部分我主要遇到了如下两个问题,其内容与解决方法如下所列:●当我写完程序,输入一段字符串让程序进行译码和解码是出现了一个问题,译出的结果不是想要的结果,但结果又有一定规律,就是结果中的字符都在明文中出现过,可是字符数量明显比明文中的要少很多。
数据结构课程设计哈夫曼编码译码器
题目一: 哈夫曼编码与译码一、任务设计一个运用哈夫曼算法的编码和译码系统, 反复地显示并解决以下项目, 直到选择退出为止。
规定:1) 将权值数据存放在数据文献(文献名为data.txt, 位于执行程序的当前目录中) ;2) 初始化:键盘输入字符集记录字符权值、自定义26个字符和26个权值、记录文献中一篇英文文章中26个字母, 建立哈夫曼树;3) 编码: 运用建好的哈夫曼树生成哈夫曼编码;4) 输出编码(一方面实现屏幕输出, 然后实现文献输出);5)译码(键盘接受编码进行译码、文献读入编码进行译码);6) 界面优化设计。
二、流程图三、代码分解 //头文献 #include<stdio.h> #include<string.h> #include<stdlib.h> #include <conio.h> #define N 1000 #define M 2*N-1 #define MAXcode 6000 //函数声明void count(CHar &ch,HTNode ht[]);void editHCode(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); //编码函数void printyima(HTNode ht[],HCode hcd[],int n,char bianma[]); //译码函数 void creatHT(HTNode ht[],int n);字符集记录符集记录权值 权值 至文献“哈夫曼树。
t xt” 菜单1.从键盘输入字符集进行编码2.从文献读入字符集进行编码1.从键盘输入编码进行译码2.从文献读入编码进行译码0.返回上级菜单 0.返回上级菜单void CreateHCode (HTNode ht[],HCode hcd[],int n);void DispHCode(HTNode ht[],HCode hcd[],int n);void input_key(CHar &ch);void input_file(CHar &ch);void input_cw(HTNode ht[]);void bianma1(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); void bianma2(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]);void yima2(HTNode ht[],HCode hcd[],int n,char bianma[]);void creat_cw();void bianmacaidan();void yimacaidan();void bianmayima();int caidan();//结构体typedef struct{char data;int parent;int weight;int lchild;int rchild;}HTNode;typedef struct{char cd[N];int start;}HCode;typedef struct{char s[N];int num;}CHar;CHar ch;HTNode ht[M];HCode hcd[N];//主函数int main(){int xh;while(1){system("color 1f"); //操作菜单背景颜色 xh=caidan(); //调用菜单函数switch(xh) //switch语句 {case 1:system("cls");creat_cw();break;case 2:system("cls");creatHT(ht,n);break;case 3:system("cls");CreateHCode(ht,hcd,n);DispHCode(ht,hcd,n);break;case 4:system("cls");bianmayima();break;case 0:system("cls");printf("\n\n\n\n\n\n\n\n\n\t\t\t\t感谢使用本系统!\n\n\n\n\n\n\n \t\t\t");exit(0);default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}return 0;}//菜单函数int caidan() //菜单函数模块//{int xh;printf("\n\n\n");printf("\t\t 欢迎使用哈夫曼编码译码系统\n");printf("\t\t \n");printf("\t\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n");printf("\t\t*= =*\n");printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n");printf("\t\t*= 1.建立字符权值=*\n");printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 2.建立并输出哈夫曼树=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 3.生成并查看哈夫曼编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 4.编码与译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 0.退出系统=*\n"); printf("\t\t*= =*\n"); printf("\t\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d", &xh);return xh; //返回从键盘接受的选项}void bianmayima(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 编码与译码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n");printf("\t\t*= 1.编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");bianmacaidan();break;case 2:system("cls");yimacaidan();break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void yimacaidan(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 译码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.键盘输入编码进行译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.文献读入编码进行译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");yima1(ht,hcd,n,bianma);break;case 2:system("cls");yima2(ht,hcd,n,bianma);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void bianmacaidan(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 编码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.键盘输入字符集编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.文献读入文章编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");bianma1(ht,hcd,ch,n,bianma);break;case 2:system("cls");bianma2(ht,hcd,ch,n,bianma);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void creat_cw(){int xh2;while(1){printf("\n\n\n\n\n");printf("\t\t 建立字符权值\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.从键盘输入字符集进行记录=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.从文献读入字符集记录=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 3.自定义字符权值=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh2);switch(xh2) //switch语句{case 1:system("cls");input_key(ch);break;case 2:system("cls");input_file(ch);break;case 3:system("cls");input_cw(ht);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}//建立字符权值模块void input_key(CHar &ch){int i,j=0;char st[N];printf("请输入字符集(以‘#’结束):\n");for(i=0;i<N;i++){scanf("%c",&st[i]);if(st[i]=='#'){st[i]='\0';break;}}strcpy(ch.s,st);count(ch,ht);printf("按任意键返回!");getch();system("cls");return;}void input_file(CHar &ch){int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&ch.s[i],sizeof(char),1,fp);}printf("读入成功!\n");printf("文献中的字符集为:%s\n",ch.s);fclose(fp);count(ch,ht);printf("按任意键返回!");getch();system("cls");return;}void input_cw(HTNode ht[]){int i,w,s,j;char a;printf("要输入的字符总个数是?:");scanf("%d",&s);n=s;printf("请输入字符及其权值:\n");for(i=0;i<s;i++){printf("请输入第%d个字母:",i+1);scanf("%s",&a);ht[i].data=a;printf("请输入其权值:");scanf("%d",&w);ht[i].weight=w;}FILE *fp;if((fp=fopen("data.txt","w"))==0){printf("\n\t\t文献打开失败");return;}printf("\n定义权值成功!\n\n");printf("各字符及其权值为:\n\n");fprintf(fp,"各字符及其权值为:\n");printf(" 字符\t权值");fprintf(fp," 字符\t权值");for(j=0;j<i;j++){ printf("\n");fprintf(fp,"\n");printf(" %-8c%-8d",ht[j].data,ht[j].weight);fprintf(fp," %-8c%-8d%",ht[j].data,ht[j].weight); }printf("\n");printf("\n字符权值已输出至文献“data.txt”!");fclose(fp);printf("输入完毕, 按任意键返回!");getch();system("cls");return;}//记录字符权值函数void count(CHar &ch,HTNode ht[]){int i,j,m=0;char c[N];int sum[N]={0};for(i=0;ch.s[i]!='\0';i++){for(j=0;j<m;j++)if(ch.s[i]==c[j]||(c[j]>='a'&&c[j]<='z'&&ch.s[i]+32==c[j])) break;if(j<m)sum[j]++;else{if(ch.s[i]>='A'&&ch.s[i]<='Z')c[j]=ch.s[i]+32;else c[j]=ch.s[i];sum[j]++;m++;}}for(i=0;i<m;i++){ht[i].data=c[i];ht[i].weight=sum[i];}n=m;FILE *fp;if((fp=fopen("data.txt","w"))==0) {printf("\n\t\t文献打开失败"); return;}printf("\n记录权值成功!\n\n"); printf("各字符及其权值为:\n\n"); fprintf(fp,"各字符及其权值为:\n"); printf(" 字符\t权值");fprintf(fp," 字符\t权值");for(j=0;j<m;j++){ printf("\n");fprintf(fp,"\n");printf(" %-8c%-8d",ht[j].data,ht[j].weight);fprintf(fp," %-8c%-8d%",ht[j].data,ht[j].weight);}printf("\n");printf("\n字符权值已输出至文献“data.txt”!");fclose(fp);}//构造哈夫曼树void creatHT(HTNode ht[],int n){FILE *fp;if((fp=fopen("哈夫曼树.txt","w"))==0){printf("\n\t\t文献打开失败");return;}int i,j,k,lnode,rnode;int min1,min2;for (i=0;i<2*n-1;i++)ht[i].parent=ht[i].lchild=ht[i].rchild=-1;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;}printf("建立huffman树成功!\n");printf("输出huffman树:\n");fprintf(fp,"输出huffman树:\n");printf("\t字符\t权值\t父节点\t 左子节点\t右子节点");fprintf(fp,"\t字符\t权值\t父节点\t 左子节点\t右子节点");for(j=1;j<i;j++){ printf("\n");fprintf(fp,"\n");printf("\t %-8c%-8d%-10d%-14d%-10d",ht[j].data,ht[j].weight,ht[j].parent,ht[i]. lchild,ht[j].rchild);fprintf(fp,"\t %-8c%-8d%-10d%-14d%-10d",ht[j].data,ht[j].weight,ht[j].parent,h t[i].lchild,ht[j].rchild);}printf("\n");printf("哈夫曼树已输出至文献“哈夫曼树.txt”!按任意键返回!");fclose(fp);getch();system("cls");return;}//生成哈夫曼编码void CreateHCode (HTNode ht[],HCode hcd[],int n){int i,f,c,j=0;HCode hc;for(i=0;i<n;i++){hc.start=n;c=i;hc.cd[hc.start--]='0';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.start++;for(j=0;j<hc.start;j++)hc.cd[j]=' ';hcd[i]=hc;}}void DispHCode(HTNode ht[],HCode hcd[],int n) {FILE *fp;if((fp=fopen("哈夫曼编码.txt","w"))==0){printf("\n\t\t文献打开失败");return;}int i,k;int sum=0,m=0,j;printf("输出字符哈夫曼编码:\n"); fputs("输出字符哈夫曼编码:\n",fp); for (i=0;i<n;i++){j=0;printf("%c:\t",ht[i].data);fprintf(fp,"\n%c:\t",ht[i].data);for (k=hcd[i].start;k<=n;k++){printf("%c",hcd[i].cd[k]);j++;fprintf(fp,"%c",hcd[i].cd[k]); }m+=ht[i].weight;sum+=ht[i].weight*j;printf("\n");}printf("\n哈夫曼编码已保存至文献“哈夫曼编码.txt!按任意键返回!”");fclose(fp);getch();system("cls");}//编码函数void bianma1(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]){int i;char str[N];printf("请输入要编码的字符集(以‘#’结束):\n");for(i=0;i<N;i++){scanf("%c",&str[i]);if(str[i]=='#'){str[i]='\0';break;}}strcpy(ch.s,str);ch.num=strlen(str);editHCode(ht,hcd,ch,n,bianma);getch();system("cls");}void bianma2(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]) {int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&ch.s[i],sizeof(char),1,fp);}ch.num=strlen(ch.s);printf("\n读入成功!\n");printf("文献中的字符集为:\n%s",ch.s);fclose(fp);editHCode(ht,hcd,ch,n,bianma);system("cls");return;}//译码函数void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]) {int i;char code[MAXcode];printf("请输入编码进行译码(以‘#’结束):\n");for(i=0;i<MAXcode;i++){scanf("%c",&code[i]);if(code[i]=='#'){code[i]='\0';break;}}strcpy(bianma,code);printyima(ht,hcd,n,bianma);printf("\n译码完毕!按任意键返回!");getch();system("cls");return;}void yima2(HTNode ht[],HCode hcd[],int n,char bianma[]) {int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&bianma[i],sizeof(char),1,fp);}printf("读入成功!\n");printf("文献中的编码是:%s\n",bianma);printyima(ht,hcd,n,bianma);printf("\n译码完毕!按任意键返回!");getch();system("cls");}四、调试结果主菜单建立字符权值选择2.从文献读入字符进行记录输入测试文献名“cs.txt”输出个字符权值建立哈夫曼树并输出至文献生成哈夫曼编码并保存至文献编码选择2.从文献读入字符集编码编码结果保存至文献译码选择2.从文献读入编码, 读入上一步的编码译码完毕, 返回!退出系统。
哈夫曼编码及译码
设计一个程序,能够利用给定的一组字符及其权值,构造哈夫曼树。
程序要求:(1)编写构造huffman 树的算法。
(2)给出哈夫曼编码算法。
(3)给出哈夫曼译码算法,并将发送的报文编码译回原文。
#include "stdio.h"# define N 9 /*叶子结点数*/# define M 2*N-1 /*总结点数*/#define maxval 1000#define codelen 100typedef int DataType;typedef struct /*哈夫曼树结点的存储结构*/{ float weight;int parent;int lchild,rchild;}HufmTree ;HufmTree tree[M+1];typedef struct /*哈夫曼编码的存储结构*/{ char bits[N]; /*保存编码的数组*/int start; /*编码的有效起始位置,从该位置之后的01串为字符的编码*/ char ch; /*字符*/}CodeType ;CodeType code[N+1]; /*字符编码数组,0号位空出*/huffman (HufmTree tree[]) /*构建哈夫曼树*/{ int i,j,p1,p2;float small_1,small_2,f;for(i=1;i<=M;i++){ tree[i].weight=0;tree[i].parent=0;tree[i].lchild=0;tree[i].rchild=0;}printf("\n\n\t请输入%d个字符的使用频率(权值):",N);for(i=1;i<=N;i++){ scanf("%f",&f);tree[i].weight=f;}for(i=N+1;i<=M;i++){ p1=1;p2=1;small_1 =maxval; small_2 =maxval;for(j=1;j<=i-1;j++)if(tree[j].parent==0)if(tree[j].weight<small_1){ small_2 =small_1; p2=p1;small_1 =tree[j].weight; p1=j;}else if(tree[j].weight<small_2){ small_2=tree[j].weight;p2=j;}tree[i].weight=tree[p1].weight+tree[p2].weight;tree[i].lchild=p1;tree[i].rchild=p2;tree[p1].parent=i;tree[p2].parent=j;}}huffmanCode(HufmTree tree[],CodeType code[]) /*哈夫曼编码*/ { int i,c,p;for(i=1;i<=N;i++){ code[i].start=N;c=i;p=tree[i].parent;while (p!=0){ code[i].start--;if(tree[p].lchild==c) code[i].bits[code[i].start] ='0';else code[i].bits[code[i].start] ='1';c=p;p=tree[p].parent;}}}decode(HufmTree tree[],CodeType code[])/*哈夫曼译码*/{ int i=M,b;int endflag=-1;int yiflag;scanf("%d",&b);while (b!=endflag){ yiflag=0;if (b==0) i=tree[i].lchild;else i=tree[i].rchild;if(tree[i].lchild==0){ printf("%c",code[i].ch);i=M;yiflag=1;}scanf("%d",&b);}if(yiflag!=1 ) printf( "\nERROR\n");}void main(){ char zifu[]={'A','B','C','D','E','F','G','H','I'}; /*待编码的字符*/int i,j,k=0;printf("\n\n\t已知%d个字符分别为:",N);/*N为全局变量,叶子结点数,即字符个数*/ for(i=1;i<=N;i++){ printf("%c ",zifu[i-1]); /*输出字符*/code[i].ch=zifu[i-1]; /*将字符保存在哈夫曼编码的存储结构中*/ }huffman(tree); /*建立哈夫曼树*/huffmanCode(tree,code); /*求得哈夫曼编码*/printf("\n\t字符的哈夫曼编码分别为:\n\t");/*输出各个字符的哈夫曼编码*/for(i=1;i<=N;i++) /*共N个字符*/{ printf("\n\t%c:",code[i].ch);for(j=code[i].start;j<N;j++) /*取出每个字符的编码*/{printf("%c",code[i].bits[j]);}}printf("\n\n\t请输入待译的0、1二进制串(-1为结束码)\n\n\t");decode(tree,code); /*输入01码,进行译码*/getchar();}运行结果如图5.33所示。
编码译码实验报告
一、实验目的1. 理解编码译码的基本原理和方法。
2. 掌握哈夫曼编码和译码的实现过程。
3. 通过实验,提高编程能力和数据结构应用能力。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 2019三、实验内容1. 哈夫曼编码与译码(1)哈夫曼编码的原理哈夫曼编码是一种变长编码,通过为不同频率的字符分配不同的编码长度,达到压缩数据的目的。
哈夫曼编码的核心是构建一棵哈夫曼树,树中每个叶子节点对应一个字符,非叶子节点对应两个子节点的编码。
(2)哈夫曼编码的实现首先,根据输入的字符及其频率,构建哈夫曼树。
然后,从根节点开始,对每个叶子节点进行编码,编码规则为从根节点到叶子节点的路径,左子节点编码为“0”,右子节点编码为“1”。
(3)哈夫曼译码的实现根据哈夫曼编码的编码规则,将编码后的数据还原成原始字符。
从编码数据的第一个比特开始,根据编码规则,逐步还原出原始字符。
2. 字符串编码与译码(1)字符串编码的原理字符串编码是将字符串中的字符转换成二进制表示,以达到压缩数据的目的。
常见的字符串编码方法有ASCII编码、UTF-8编码等。
(2)字符串编码的实现以ASCII编码为例,将字符串中的每个字符转换为对应的ASCII码,然后将其转换为二进制表示。
(3)字符串译码的实现将编码后的二进制数据转换回对应的ASCII码,再将ASCII码转换成字符。
四、实验步骤1. 创建一个新的C++项目,命名为“编码译码实验”。
2. 在项目中创建两个源文件:main.cpp和编码译码.cpp。
3. 在main.cpp中编写代码,实现以下功能:(1)从文件中读取字符串,进行哈夫曼编码。
(2)将编码后的数据写入文件。
(3)从文件中读取编码后的数据,进行哈夫曼译码。
(4)将译码后的字符串输出到屏幕。
4. 在编码译码.cpp中编写代码,实现以下功能:(1)构建哈夫曼树。
(2)实现哈夫曼编码和译码算法。
哈夫曼编码译码实训报告
一、实训目的本次实训旨在通过实际操作,使学生掌握哈夫曼编码的基本原理和方法,熟悉哈夫曼树的构建过程,并能够熟练地进行哈夫曼编码和译码操作。
通过实训,提升学生对数据压缩技术的理解和应用能力。
二、实训内容1. 哈夫曼树构建- 收集给定字符串中每个字符的出现频率。
- 根据字符频率构建哈夫曼树,其中频率高的字符对应较大的权重。
- 使用优先队列(最小堆)实现哈夫曼树的构建。
2. 哈夫曼编码- 遍历哈夫曼树,为每个叶子节点分配唯一的编码,左分支为0,右分支为1。
- 根据分配的编码生成字符编码表。
3. 哈夫曼译码- 使用生成的编码表,将编码字符串转换回原始字符串。
三、实训步骤1. 数据准备- 选择一段英文或中文文本作为输入数据。
2. 构建哈夫曼树- 统计输入数据中每个字符的出现频率。
- 使用优先队列构建哈夫曼树。
3. 生成哈夫曼编码- 遍历哈夫曼树,为每个叶子节点分配编码。
- 生成字符编码表。
4. 编码数据- 使用哈夫曼编码表对输入数据进行编码。
5. 译码数据- 使用哈夫曼编码表对编码后的数据进行译码。
6. 结果分析- 比较编码前后数据的大小,分析哈夫曼编码的压缩效果。
四、实训结果1. 哈夫曼树构建- 成功构建了给定字符串的哈夫曼树。
2. 哈夫曼编码- 成功生成了每个字符的哈夫曼编码。
3. 哈夫曼译码- 成功将编码后的数据译码回原始字符串。
4. 压缩效果分析- 通过对比编码前后数据的大小,验证了哈夫曼编码的压缩效果。
五、实训总结1. 哈夫曼编码原理- 哈夫曼编码是一种基于字符频率的变长编码方法,能够有效降低数据传输的冗余度。
2. 哈夫曼树构建- 哈夫曼树的构建是哈夫曼编码的关键步骤,通过优先队列(最小堆)实现。
3. 哈夫曼编码与译码- 哈夫曼编码和译码过程相对简单,但需要正确处理编码表和字符编码。
4. 实训收获- 通过本次实训,掌握了哈夫曼编码的基本原理和方法,熟悉了哈夫曼树的构建过程,并能够熟练地进行哈夫曼编码和译码操作。
哈夫曼编码译码
哈夫曼编码/译码一、实验内容利用哈夫曼编码进行住处通讯可以大大提高信道利用率,缩短住处传输时间,降低成本,但是,这要求在发送端通过一个编码系统将传输的数据预先编码,在接收端通过一个译码系统对传来的数据进行译码(复原),对于双向传输信息的信道,每端都一个完整的编码译码系统,试为这样的住处收发站写一个哈夫曼友的编码译码系统.测试数据:用下表给出的字符集和频度的计数据建立哈曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FA VORITE”.。
字符 A B C D E F G H I J K L M频数186 64 13 22 32 103 21 15 47 57 1 5 32 20字符N O P Q R S T U V W X Y Z频数57 63 15 1 48 51 80 23 8 18 1 16 1二、实验目的树型结构是一种应用极为广泛的非线性数据结构,也是本课程的重点内容,哈夫曼树(最优二叉树)是树型结构的典型应用,本次实验突出了数据结构加操作的程序设计观点,希望能根据树型结构的非线性特点,熟悉各种存储结构的特性,达到如何应用树型结构的非线性特点,熟悉各种存储结构的特性,达到如何应用树型结构解决具体问题的目的.三、实验步骤:1、需求分析1)、利用哈夫曼编码进行信息通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(既可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
本次设计就是为这样的信息收发站写的一个哈夫曼的编/译码器。
本实验要求:2)、本演示程序中,用户可以输入键盘中的任意字符,长度为任意长,字符输入顺序不限,且允许出现重码3)、演示程序以用户与计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令,相应的输入数据(可虑去输入中的非法字符)和运算结果显示在其后。
哈弗曼编码与译码
一个完整的系统应具有以下功能:(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 中。
2.测试要求(1) 已知某系统在通信联络中只可能出现八种字符,其频率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。
(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FA VORITE”。
3.实现提示(1) 编码结果以文本方式存储在文件Codefile中。
(2) 用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”,表示退出运行Quit。
请用户键入一个选择功能符。
此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
(3) 在程序的一次执行过程中,第一次执行I,D或C命令之后,赫夫曼树已经在内存了,不必再读入。
每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。
#include <string.h>#include <stdio.h>#include <stdlib.h>#include <malloc.h>typedef struct {char letter;float wt;}hfm,*hfmlist;//*************************全局变量************************************ unsigned int s1,s2,n;char choose;int DEPTH=0;char a[20];//***************Huffman树和Huffman编码的存储表示********************** typedef struct{unsigned int weight;unsigned int code;unsigned int parent,lchild,rchild;}HTNode, *HuffmanTree; //动态分配数组存储Huffman树typedef char * *HuffmanCode; //动态分配数组存储Huffman编码表//***************************初始化Huffman树*************************** void select(HuffmanTree HT,int l){int a,b,c,j;s1=s2=1;a=b=1000;for(j=1;j<=l;j++){if(HT[j].code==0){c=HT[j].weight;if(c<a){b=a;a=c;s2=s1;s1=j;}else if(c<b){b=c;s2=j;}}//if}//forHT[s1].code=HT[s2].code=1;}//selectvoid HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC, hfmlist HL,unsigned int n){ //w存放n个权值(均>0),构造Huffman树HT,并求出n个字符的Huffman编码HC. unsigned int i,f,start,c,m;char*cd;if (n<=1) return;m =2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));for(i=1;i<=m;++i){HT[i].weight=HT[i].parent=HT[i].lchild=HT[i].rchild=HT[i].code=0;} for(i=1;i<=n;++i)HT[i].weight=HL[i].wt;for (i=n+1;i<=m;++i){select(HT,i-1);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=(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';else cd[--start]='1';HC[i]=(char*)malloc((n-start)*sizeof(char));strcpy(HC[i],cd+start);}free(cd);}//*************************文件操作*****************************void save (char *p){FILE *fp;int i;printf("input the name:");if((fp=fopen(gets(a),"w+"))==NULL){printf("cannot open the file!\n");exit(0);}//iffor(i=0;p[i]!='\0';i++){if(fwrite(p+i,sizeof(char),1,fp)!=1){//fwrite函数写数据块printf(" error!\n");exit(0);}//if}//forfclose(fp);}//save//************************编码与译码操作********************************** void Decoding(HuffmanTree HT,hfmlist HL,char*size,int n)//这个函数是用来译码的{int i,j,k;char p[130];printf("请输入需要译码的代码:");gets(p);//接受需要译码的字符串i=2*n-1;k=0;for(j=0;p[j]!='\0';j++){if(p[j]=='0'){ if(HT[i].lchild!=0)i=HT[i].lchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}else{ if(HT[i].rchild!=0)i=HT[i].rchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}}}//forif( p[j-1]=='0')size[k++]=HL[i].letter;else size[k++]=HL[i].letter;size[k]='\0';}//decodingvoid Encoding(HuffmanCode HC,hfmlist HL,char *coding,int n){int i,j,t,k=0;char p[100];printf("请再次输入需要编码的文本:");gets(p);for(i=0;p[i]!='\0';i++){if((p[i]>='A'&&p[i]<='Z')||p[i]==' ')for(j=1;j<=n;j++)if(p[i]==HL[j].letter)for(t=0;HC[j][t]!='\0';t++)coding[k++]=HC[j][t];}//forcoding[k]='\0';}//encoding//************************打印操作**************************** void Print(FILE *fp1,FILE *fp2){//将文件fp1中的代码以紧凑格式显示在终端上,每行50个代码//同时将此字符形式的编码文件写入文件fp2中char c[200];int i;fgets(c,200,fp1);for(i=0;c[i]=='0'||c[i]=='1';i++){printf("%c",c[i]);fprintf(fp2,"%c",c[i]);if((i+1)/50*50==(i+1)){printf("\n");fprintf(fp2,"\n");}}//forprintf("\n");}//Printvoid PreOrderTraverse(HuffmanTree HT,int k,FILE *fp){//先序遍历并打印树,结果存放于fp中,k为根结点的下标int i;for(i=1;i<=DEPTH-1;i++)fprintf(fp," ");for(;i<=DEPTH;i++)fprintf(fp,"|------");fprintf(fp,"%d\n",HT[k].weight);if(HT[k].lchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].lchild,fp);DEPTH--;}if(HT[k].rchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].rchild,fp);DEPTH--;}if(HT[k].lchild==0&&HT[k].rchild==0)return;return;} //PreOrderTraversevoid TreePrinting(HuffmanTree HT,int n,FILE *fp){//打印树HT,结果存于文件fp中,n为树的叶子结点数int i,k;for(i=1;i<=2*n;i++)if(HT[i].parent==0){k=i;break;}//寻找根结点PreOrderTraverse(HT,k,fp);return;}//TreePrinting//**************************主函数*********************************int main(){FILE *fp1,*fp2,*fp3,*fp4,*fp5;HuffmanTree HT;HuffmanCode HC;hfmlist HL;unsigned int i,n;char *b,c[100],cha,ch;b=(char *)malloc(100*sizeof(char));printf("请选择操作:\n");printf("i:初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");b=(char *)malloc(100*sizeof(char));HL=(hfmlist)malloc(30*sizeof(hfm));//存储字符与权值,线性表长30printf("\n");printf("选择操作(i,e,d,p,t,q):");ch=getchar();getchar();printf("\n");do{switch(ch){case 'i':printf("正在进行初始化……\n");printf("输入字符长度:");scanf("%d",&n);getchar();printf("\n");HC=(HuffmanCode)malloc((n+1)*sizeof(char));HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode));for(i=1;i<=n;i++){printf("请输入第%d个字符及权值(格式:字符权值):",i);scanf("%c %f",&(HL+i)->letter, &(HL+i)->wt);getchar();}//forif((fp5=fopen("hfmTree.txt","w"))==NULL){printf("cannot open file!\n");exit(0);}//iffor(i=1;i<=n;i++){fprintf(fp5,"第%d个字符及权值:\t\t\t",i);fprintf(fp5,"%c %f\n",(HL+i)->letter,(HL+i)->wt);}//forfclose(fp5);HuffmanCoding(HT,HC,HL,n);printf("\n已经将Huffman树存入文件hfmTree.txt中\n\n");printf("初始化完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n\n");break;case 'e':printf("请输入编码,以#结尾:");if((fp2=fopen("ToBeTran.txt","w"))==NULL){printf("cannot open file\n");exit(0);}//ifcha=getchar();while(cha!='#'){fputc(cha,fp2);cha=getchar();}//whilegetchar();fclose(fp2);printf("已经把编码存入文件ToBeTran.txt中\n\n");Encoding(HC,HL,b,n);printf("文本的哈夫曼编码是:");printf("%s\n",b);printf("下面进行保存:");save(b);printf("编码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'd':Decoding(HT,HL,c,n);printf("输入要译码的编码:");printf("正在进行译码……\n");printf("%s\n",c);save(c);printf("已经将结果存入文件%s中\n",a);printf("译码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'p':for(i=1;i<=n;i++)printf("字符:%c\t\t\t译码:%s\n",HL[i].letter,HC[i]);if((fp1=fopen("Code","w"))==NULL){printf("cannot open the file!\n");exit(0);}//ifif((fp4=fopen("Code","r"))==NULL){printf("cannot open the file!\n");exit(0);}//ifPrint(fp4,fp1);printf("该代码文件已经存在并命名为CodePrin.txt\n");fclose(fp4);fclose(fp1);break;case 't':printf("打印树存在于文件TreePrin中\n");if((fp3=fopen("TreePrin.txt","w"))==NULL) {printf("cannot open file\n");exit(0);}TreePrinting(HT,n,fp3);fclose(fp3);break;case 'q':exit(0);break;default :exit(0);break;}//switchprintf("\n请选择操作(i,e,d,p,t,q):");ch=getchar();getchar();}while(ch!='q');//doreturn 0 ;}//main。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
min2=t[j].weight;
*p2=j;
}
}
}
void crபைடு நூலகம்athfmt(hfmt t)
fclose(p);
n=i;
printf("\nn=%d",n);
for(i=0;i<2*n-1;i++)
{
t[i].lchild=-1;
t[i].rchild=-1;
#include <string.h>
#define MAXLEN 10
typedef struct
{
int weight;
int lchild;
int rchild;
int parent;
char key;
char mima[100];
q->front=q->rear=0;
return q;
}
void inithfmt(hfmt t)
{
int i,j,k;
FILE *p;
char ch;
i=0;
p=fopen("1.txt","r");
}
else
{
printf("1");
}
}
void huffmannode(hfmt t)
{
int i,j,a;
}htnode;
typedef htnode hfmt[MAXLEN];
int n=0;
typedef char elemtype;
typedef struct
{
elemtype data[MAXLEN];
int front,rear;
}seqqueue;
t[p2].parent=i;
t[i].lchild=p1;
t[i].rchild=p2;
t[i].weight=t[p1].weight+t[p2].weight;
}
int j;
for(j=0;j<=i;j++)
{
if(t[j].parent==-1)
if(min1>t[j].weight)
{
min1=t[j].weight;
void enqueue(seqqueue *q,char item)
{
q->data[q->rear]=item;
q->rear=q->rear+1;
}
elemtype dequeue(seqqueue *q)
{
elemtype item;
if(q->rear!=q->front)
i=j;
hfnode2(t,q,i,j);
}
if(t[b].lchild==a)
{
item='0';
enqueue(q,item);
{
printf("\n");
printf("%d\t%d\t%d\t%d\t%c\t%s",t[i].weight,t[i].parent,t[i].lchild,t[i].rchild,t[i].key);
printf("the code is:");
for(i=0;i<n;i++)
{
j=0;
printf("\n");
printf("%c(%d):",t[i].key,t[i].weight);
if(fopen("1.txt","r")==NULL)
printf("open error.");
while((ch=fgetc(p))!=EOF)
{
for(k=0;k<i;k++)
{
}
else
{
item='1';
enqueue(q,item);
}
}
void decoding(hfmt t,seqqueue *q)
hfnode1(t,i,j);
}
}
void Encoding(hfmt t)
{
char r[1000],ch;
int i=0,j;
FILE *p;
p=fopen("2.txt","r");
if(fopen("2.txt","r")==NULL)
t[i].key=ch;
t[i].weight++;
i++;
}
else
t[k].weight++;
}
if(t[j].parent!=-1)
{
i=j;
hfnode1(t,i,j);
}
if(t[b].lchild==a)
{
printf("0");
}
void printhfmt(hfmt t)
{
int i;
printf("\nthe hfmt is:\n");
printf("weight\tparent\tlchild\trchild\tkey\t");
for(i=0;i<2*n-1;i++)
*p1=j;
}
}
for(j=0;j<=i;j++)
{
if(t[j].parent==-1)
if(min2>t[j].weight && j!=(*p1))
{
int i,p1,p2;
inithfmt(t);
for(i=n;i<2*n-1;i++)
{
selectmin(t,i-1,&p1,&p2);
t[p1].parent=i;
t[i].parent=-1;
}
}
void selectmin(hfmt t,int i,int *p1,int *p2)
{
long min1=999999;
long min2=999999;
while((ch=fgetc(p))!=EOF)
{
r[i++]=ch;
}
fclose(p);
len=strlen(r);
for(i=0;i<n;i++)
{
hfnode2(t,q,i,j);
for(j=0;j<n;j++)
t[i].mima[j]=dequeue(q);
{
item=q->data[q->front];
q->front=q->front+1;
return item;
}
}
seqqueue *initqueue(seqqueue *q)
{
q=(seqqueue *)malloc(sizeof(seqqueue));
}
void hfnode2(hfmt t,seqqueue *q,int i,int j)
{
int a,b,c=0;
char item;
a=i;
b=j=t[i].parent;
if(t[j].parent!=-1)
{
{
char r[100],ch;
FILE *p;
int i=0,j=0,len,x,y,s=0;
x=2*n-2;
p=fopen("3.txt","r");
if(fopen("3.txt","r")==NULL)
printf("\nopen error.");
if(t[k].key==ch)
break;
}
if(k==i)
{
t[i].weight=0;
(1)输入一组字符集的大小、字符及权值,建立哈夫曼树,显示该哈夫曼树,并给出每个字符的哈夫曼编码
(2)给出一串字符,按照已建立的哈夫曼树进行编码,显示结果或存入文件
(3)用(2)的结果,按照哈夫曼树进行译码
#include <stdio.h>
#include <stdlib.h>
for(j=0;r[j]!='\0';j++)
for(i=0;i<n;i++)
if(r[j]==t[i].key)
{
hfnode1(t,i,j);
}
printf("\n\nopen error.");
while((ch=fgetc(p))!=EOF)
{
r[i++]=ch;
}
fclose(p);
printf("\n\nth Encoding is:");
}
printf("\n\n");
}