一:问题描述
【问题描述】
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼码的编/译码系统。
【任务要求】
一个完整的系统应具有以下功能:
1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
2) E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
3) D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
【测试数据】
用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。
字符 | 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.构建哈夫曼树
有n个字母待建树,申请p[2n-1]个结构体数组空间,将各个字母及其权值存入结构体数组,将数组按照权值进行排序,每次选取最小的两个构建哈夫曼树,每次从上次选择的下一个开始选择,即第一次p[0],p[1]则第二次p[2],p[3],以此类推,每次生成的从p[n+1]开始存入,直至数组就剩下一个元素,即为根节点。
2.编码
从叶子结点(带权字母即叶子结点,从1步骤的结构体数组那里入手,需要判断一下是否为叶子结点)开始向上回溯即寻找父节点,若为父节点左子树编码为‘0’字符,反之为‘1’字符,建个数组从最后一位往前存入直至父节点为空即根节点,直至结构体数组最后一个元素。然后将存储的字母的编码和待编码的字符串进行比对,将字符串译码为01结构,编码完成。
3.译码
将01结构的编码从根节点开始译码,0往左子树遍历1往右子树,直至叶节点,译码出一个字母,然后再从根节点开始,循环操作直至所有都译码完成。
三:具体实现
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; typedef struct node { char ch[2]; int weight; char ldata,rdata; node *lchild,*rchild,*parent; }*huffman; typedef struct encoding { char ch[2]; char *data; }*encode1; void paixu(huffman *p,int m) { huffman temp; for(int i=0;i<m-1;i++) { for(int j=i+1;j<m;j++) { if(p[i]->weight>p[j]->weight) { temp=p[i]; p[i]=p[j]; p[j]=temp; } } } } huffman* Read(int n) //读取英文字母 { huffman *huff; FILE *fp; huff=new huffman[2*n-1]; for(int i=0;i<2*n-1;i++) { huff[i]=new node; huff[i]->lchild=huff[i]->rchild=NULL; } if((fp=fopen("hfmTree.txt","w"))==NULL) {cout<<"文件打开失败!";exit(0);} cout<<"please input the letter:"<<endl; for(int i=0;i<n;i++) { huff[i]->ch[0]=cin.get(); if(huff[i]->ch[0]==' ') huff[i]->ch[0]=cin.get(); cin>>huff[i]->weight; cin.get(); huff[i]->ch[1]='