简单的哈夫曼树英文翻译系统

it2024-04-04  65

哈夫曼编码和译码 基本要求:  输入为:一段英文或中文的文章(原文)  对输入的文章构造哈夫曼树生成对应的编码  输出为:原文所对应的编码(译文)  根据已经生成的编码表,输入任意的译文可以得到对应的原文

哈夫曼树的定义:给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

首先先构造一棵哈夫曼树,在构造哈夫曼树的算法中,需要选择根权值最小和次小的树进行合并

//建立哈夫曼树编码表 void HuffmanTree::CreatHuffmanTree(int a[],char b[],int n) { int m=2*n-1; nodes= new HuffmanTreeNode[2*n-1];//开辟数组空间 for(int i=0;i<n;i++) //初始化结点为-1 { nodes[i].weight=a[i]; //函数头定义的权值数组a[] nodes[i].leftChild=-1; nodes[i].rightChild=-1; nodes[i].parent=-1; } for(i=n; i<m;i++) { int r1=0,r2=0; select(r1,r2,i); //合并两个根权值最小的树 nodes[r1].parent=nodes[r2].parent=i; nodes[i].leftChild=r1; nodes[i].rightChild=r2; nodes[i].parent=-1; nodes[i].weight=nodes[r1].weight+nodes[r2].weight; } //查找两个权值最小的树 void HuffmanTree::select(int &r1,int &r2,int n) { r1=r2=-1; for(int i=0; i<n; i++) if(nodes[i].parent==-1) //找权值最小的双亲节点 if(r1==-1) r1=i; else if(nodes[r1].weight<nodes[i].weight) { r2=r1;//r2等于次小的 r1=i;//r1等于最大的 } else if(r2==-1||nodes[i].weight<nodes[r2].weight)//找权值第二小的结点 r2=i; } ```cpp 在这里插入代码片

建立编码表,根据每一根分支是左还是右,确定相应位编码是0还是1(此代码为左0右1),从叶子节点出发逆向到根结点,将编码倒转使之成为正确的编码

//建立编码表 void HuffmanTree::CreatHuffmanTree(int a[],char b[],int n) { codes=new HuffmanCode[n]; for( i=0; i<n; i++) { codes[i].data=b[i];//将编码后的结果储存在b数组中 int q=i; int p=nodes[i].parent;//p指向结点i的双亲 int k=0; while(p!=-1)//逆向求码 { if(q==nodes[p].leftChild) codes[i].code[k]='0'; //左0 else codes[i].code[k]='1'; //右1 k++;//向下往上查找双亲 q=p; p=nodes[q].parent; } codes[i].code[k]='\0'; recall(codes[i].code,k); //字符串整合,倒转 cout<<codes[i].data<<"的编码是:"<<codes[i].code<<endl; } } //倒转字符串 void HuffmanTree::recall(char c[],int L) { L=0; char temp; while(c[L+1]!='\0')//获取当前编码的长度 { L++; } for(int i=0;i<=L/2;i++)//交换位置 { temp=c[i]; c[i]=c[L-i]; c[L-i]=temp; } }

有了哈夫曼树的编码,即可进行编码和译码

//编码 void HuffmanTree::Encode(char *c, char *s,int n) { while(*c!='\0') { for(int i=0;i<=n-1;i++) //遍历查找编码 { if(*c==codes[i].data) { strcat(s,codes[i].code);//复制连接字符串 break; } } c++; } cout<<"编码结果为:"<<s<<endl; } //译码 void HuffmanTree::Decode(char *s, char *d,int n) { int z=2*n-2; char *p=d; while(*s!='\0')//编码的逆过程 { while(nodes[z].leftChild!=-1) { if(*s=='0') //如果*s==0,给根结点的左孩子的下标值赋值z并把左孩子作为新的根结点 z=nodes[z].leftChild;//左0 else if(*s=='1') z=nodes[z].rightChild;//右1 s++; } *d=codes[z].data;//译码后的结果赋值给指针*d d++; } cout<<endl<<"译码结果为:"<<p<<endl; }

主要函数就是以上,下面将程序变得完整一点,使其成为可运行的程序 主函数如下:

void main() { HuffmanTree HT; //system("color b0"); //system("color f4"); cout<<"---------------------------------------"<<endl; cout<<" 欢迎使用哈夫曼编码系统 "<<endl; cout<<"---------------------------------------"<<endl; cout<<" 请输入英文段落: "<<endl; char *A1=new char[50];//定义字符指针,开辟空间设置字符长度 char *B1=new char[50]; *B1='\0';//字符串结束标志 gets(A1);//得到从键盘输入的字符串A1 int n = HT.sumweight(A1);//计算A1字符串的频率 char *A2=new char[50]; for(int i=0;i<=49;i++) *(A2+i)='\0'; //到A2+1个字符结束 cout<<"按任意字符继续。"<<endl; getch(); HT.menu(); while(true) { int w; cin>>w; switch(w) { case 1: HT.CreatHuffmanTree(I,H,n); getch(); cout<<"按任意字符继续。"<<endl; //system("cls");可选择清屏或不清屏 HT.menu(); break; case 2: HT.Encode(A1,B1,n); cout<<"按任意字符继续。"<<endl; getch(); //system("cls"); HT.menu(); break; case 3: gets(B1); cout<<endl<<"请输入想要翻译的一串二进制编码:"<<endl; gets(B1); HT.Decode(B1,A2,n); cout<<"按任意字符继续。"<<endl; getch(); //system("cls"); HT.menu(); break; case 4: cout << endl; cout << "退出成功!" << endl; exit(0); break; default: cout<<"选择失败,请重新选择!"<<endl; cout<<endl; break; } } }

哈夫曼树是带权路径长度最小的树,所以将一段英文里出现字符的频率作为权值来计算

//计算字符出现的频率 int HuffmanTree::sumweight(char *pl) { char *sweight=pl; int i=0; H[0]=*sweight; I[0]=0; while(*sweight!='\0') { for(int j=0;j<=i;j++) { if(H[j]==*sweight) { I[j]++; break; } } if(j>i) { i++; H[i]=*sweight; I[i]=1; } sweight++; } cout<<endl<<"统计次数:"<<endl; for(int j=0;j<=i;j++) cout<<"字符"<<H[j]<<"的频率为"<<I[j]<<endl; return i+1; }

至此,程序基本已经完善,剩下的函数成员以及结构体可在调试时自行加上。

最新回复(0)