哈夫曼编码器
整理了一下最近做的数据结构上机实习题:
【问题描述】 利用哈夫曼编码进行信息通讯可以大大提高信道利用率,缩短信息 传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对 待传数据预先编码;在接收端将传来的数据进行译码(复原)。对于双 工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码 系统。试为这样的信息收发站写一个哈夫曼码的编译码系统。
【基本要求】 一个完整的系统应具有以下功能: (1)I:初始化(Initialization)。从终端读入字符集大小n,及n个 字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree中。 (2)C:编码(Coding )。利用已建好的哈夫曼树(如不在内存, 则从文件hfmtree中读入),对文件tobetrans中的正文进行编码,然后 将结果存入文件codefile中。 (3)D:译码(Decoding)。利用已建好的哈夫曼树将文件codefile 中的代码进行译码,结果存入文件textfile中。
(4)P:印代码文件(Print)。将文件codefile以紧凑格式显示在终端 上,每行50个代码。同时将此字符形式的编码文件写入文件codeprint中。 (5)T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以 直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫 曼树写入文件treeprint中。
【测试数据】 (1)已知某系统在通信联络中只可能出现八种字符,其频率分别为 0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计哈夫曼编码。 (2)实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。
【实现提示】 (1)用户界面可以设计为“菜单”方式:显示上述功能符号,再加上 “E”,表示结束运行End,请用户键入一个选择功能符。此功能执行完毕 后再显示此菜单,直至某次用户选择了“E”为止。 (2)程序的一次执行过程中,第一次执行I、D或C命令之后,哈夫曼 树已经在内存了,不必再读入。每次执行中不一定执行I命令,因为文件 hfmtree可能早已建好。
haffman.h
1 typedef struct { 2 char data; 3 int weight ; 4 int flag; 5 int parent ; 6 int leftChild ; 7 int rightChild ; 8 }HaffNode ; 9 10 typedef struct { 11 char bit[MaxNode]; 12 int start ; 13 int weight ; 14 char data ; 15 }Code ; 16 17 void Haffman(int weight[],char str[],int n,HaffNode haffTree[]) 18 { 19 int i,j,m1,m2,x1,x2 ; 20 for(i=0;i<2*n-1;i++){ 21 if(i<n) { 22 haffTree[i].weight=weight[i]; 23 haffTree[i].data=str[i]; 24 }else { 25 haffTree[i].weight=0; 26 haffTree[i].data='0'; 27 } 28 haffTree[i].parent=-1; 29 haffTree[i].flag=0; 30 haffTree[i].leftChild=-1; 31 haffTree[i].rightChild=-1; 32 } 33 for(i=0;i<n-1;i++){ 34 m1=m2=MaxValue ; 35 x1=x2=0; 36 for(j=0;j<n+i;j++){ 37 if(haffTree[j].weight<m1&&haffTree[j].flag==0){ 38 m2=m1; 39 x2=x1; 40 m1=haffTree[j].weight; 41 x1=j; 42 }else if(haffTree[j].weight<m2&&haffTree[j].flag==0) 43 { 44 m2=haffTree[j].weight; 45 x2=j ; 46 } 47 } 48 haffTree[x1].parent=n+i; 49 haffTree[x2].parent=n+i; 50 haffTree[x1].flag=haffTree[x2].flag=1; 51 haffTree[n+i].weight=haffTree[x1].weight+haffTree[x2].weight; 52 haffTree[n+i].leftChild=x1; 53 haffTree[n+i].rightChild=x2; 54 } 55 } 56 57 void HaffmanCode(HaffNode haffTree[],int n,Code haffCode[]) 58 { 59 Code *cd=(Code *)malloc(sizeof(Code)); 60 int i,j,child,parent ; 61 for(i=0;i<n;i++){ 62 cd->start=n-1; 63 cd->weight=haffTree[i].weight; 64 cd->data=haffTree[i].data ; 65 child=i; 66 parent=haffTree[child].parent ; 67 while(parent!=-1){ 68 if(haffTree[parent].leftChild==child) 69 cd->bit[cd->start]='0'; 70 else 71 cd->bit[cd->start]='1'; 72 73 cd->start--; 74 child=parent ; 75 parent=haffTree[child].parent; 76 } 77 for(j=cd->start+1;j<n;j++) 78 haffCode[i].bit[j]=cd->bit[j]; 79 haffCode[i].bit[j]='\0'; 80 haffCode[i].start=cd->start+1; 81 haffCode[i].weight=cd->weight; 82 haffCode[i].data=cd->data; 83 } 84 }
1 #include<iostream> 2 #include<iomanip> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<string> 7 #include<fstream> 8 #define MaxValue 32767 9 #define MaxNode 10000 10 #include"Haffman.h" 11 using namespace std ; 12 13 ifstream input_file ; 14 ofstream output_file ; 15 int n,m=0; 16 HaffNode *myHaffTree=(HaffNode *)malloc(sizeof(HaffNode)*(2*MaxNode-1)); 17 Code *myHaffCode=(Code *)malloc(sizeof(Code)*MaxNode); 18 19 void Initialization(){ 20 char str[MaxNode]; 21 int weight[MaxNode]; 22 cout<<"请输入字符个数:"<<endl; 23 cin>>n; 24 for(int i=0;i<n;i++){ 25 cout<<"请输入第"<<i+1<<"个字符以及相应的权值"<<endl; 26 cin>>str[i]>>weight[i]; 27 } 28 29 Haffman(weight,str,n,myHaffTree); 30 HaffmanCode(myHaffTree,n,myHaffCode); 31 32 for(int i=0;i<n;i++){ 33 cout<<myHaffCode[i].data<<": "; 34 for(int j=myHaffCode[i].start;j<n;j++){ 35 cout<<myHaffCode[i].bit[j]; 36 } 37 cout<<endl; 38 } 39 40 output_file.open("hfmTree.txt"); 41 if(!output_file){ 42 cout<<"can't open file !"<<endl; 43 return ; 44 } 45 for(int i=0;i<n;i++){ 46 output_file<<"("<<myHaffTree[i].data<<myHaffTree[i].weight<<")"<<endl; 47 } 48 output_file.close(); 49 cout<<"哈夫曼树已创建完成,并且已放入hfmTree.txt中."<<endl; 50 cout<<endl<<endl; 51 } 52 53 void Coding(){ 54 cout<<"请输入字符或字符串:"<<endl; 55 string str ; 56 string code ; 57 cin>>str; 58 output_file.open("tobetran.txt"); 59 if(!output_file){ 60 cout<<"can't open file !"<<endl; 61 return ; 62 } 63 output_file<<str; 64 output_file.close(); 65 output_file.open("codefile.txt"); 66 if(!output_file){ 67 cout<<"can't open file !"<<endl; 68 return ; 69 } 70 for(int i=0;i<str.size();i++){ 71 for(int j=0;j<n;j++){ 72 if(myHaffTree[j].data==str[i]){ 73 for(int k=myHaffCode[j].start;k<n;k++){ 74 output_file<<myHaffCode[j].bit[k]; 75 } 76 break; 77 } 78 } 79 } 80 output_file.close(); 81 cout<<"编码完毕,并且已经存入codefile.txt中!"<<endl; 82 input_file.open("codefile.txt"); 83 if(!input_file){ 84 cout<<"can't open file !"<<endl; 85 return ; 86 } 87 input_file>>code; 88 cout<<"编码码值为:"<<endl; 89 cout<<code<<endl; 90 input_file.close(); 91 cout<<endl<<endl; 92 } 93 94 95 void Decoding(){ 96 char s[MaxNode],s1[MaxNode]; 97 int i,j,k,l,p; 98 input_file.open("codefile.txt"); 99 if(!input_file){ 100 cout<<"can't open file !"<<endl; 101 return ; 102 } 103 input_file>>s; 104 input_file.close(); 105 output_file.open("textfile.txt"); 106 if(!output_file){ 107 cout<<"can't open file !"<<endl; 108 return ; 109 } 110 k=0; 111 while(s[k]!='\0'){ 112 for( i=0;i<n;i++){ 113 l=k; 114 for( j=0;j<strlen(myHaffCode[i].bit)-myHaffCode[i].start;j++,l++){ 115 s1[j]=s[l]; 116 } 117 s1[j]='\0'; 118 for(p=myHaffCode[i].start,j=0;p<n;p++,j++) 119 if(myHaffCode[i].bit[p]!=s1[j]) break; 120 if(p==n){ 121 output_file<<myHaffTree[i].data; 122 k+=strlen(myHaffCode[i].bit)-myHaffCode[i].start; 123 break; 124 } 125 } 126 } 127 output_file.close(); 128 input_file.open("textfile.txt"); 129 if(!input_file){ 130 cout<<"can't open file !"<<endl; 131 return ; 132 } 133 input_file>>s; 134 cout<<s<<endl; 135 input_file.close(); 136 cout<<"译码结束,字符已经存入textfile.txt文件中!"<<endl; 137 cout<<endl<<endl; 138 } 139 140 void Print(){ 141 char s[MaxNode],s1[MaxNode]; 142 int i,j,k,l,p; 143 input_file.open("codefile.txt"); 144 if(!input_file){ 145 cout<<"can't open file !"<<endl; 146 return ; 147 } 148 input_file>>s; 149 int icount=0; 150 for(int i=1;i<strlen(s)+1;i++){ 151 cout<<s[i-1]; 152 if(i%50==0) cout<<endl; 153 } 154 cout<<endl; 155 input_file.close(); 156 output_file.open("codeprint.txt"); 157 k=0; 158 while(s[k]!='\0'){ 159 for( i=0;i<n;i++){ 160 l=k; 161 for( j=0;j<strlen(myHaffCode[i].bit)-myHaffCode[i].start;j++,l++){ 162 s1[j]=s[l]; 163 } 164 s1[j]='\0'; 165 for(p=myHaffCode[i].start,j=0;p<n;p++,j++) 166 if(myHaffCode[i].bit[p]!=s1[j]) break; 167 if(p==n){ 168 output_file<<myHaffTree[i].data; 169 k+=strlen(myHaffCode[i].bit)-myHaffCode[i].start; 170 break; 171 } 172 } 173 } 174 output_file.close(); 175 cout<<"字符形式的编码文件写入文件codeprint中!"<<endl; 176 cout<<endl<<endl; 177 } 178 179 void TreePrinting(HaffNode *myHaffTree1,HaffNode *myHaffTree2,int m){ 180 if(myHaffTree1!=myHaffTree2-1) 181 { 182 if(m)output_file.close(); 183 output_file.open("treeprint.txt"); 184 if(!output_file){ 185 cout<<"can't open file !"<<endl; 186 return ; 187 } 188 TreePrinting(myHaffTree2+myHaffTree1->rightChild,myHaffTree2,m+1); 189 cout<<setw(4*m)<<myHaffTree1->weight<<endl; 190 output_file<<myHaffTree1->weight<<endl; 191 TreePrinting(myHaffTree2+myHaffTree1->leftChild,myHaffTree2,m+1); 192 output_file.close(); 193 } 194 } 195 196 197 int main(){ 198 char ch ; 199 while(1){ 200 cout<<" *******************哈夫曼编/译码器****************"<<endl; 201 cout<<" I---Initialization"<<" C---Coding"<<endl; 202 cout<<" D---Decoding"<<" P---Print"<<endl; 203 cout<<" T---Tree printing"<<" E---Exit"<<endl; 204 cout<<" ------------------------------------------"<<endl; 205 cout<<"please select a function key:"<<endl; 206 cin>>ch; 207 if(ch=='I') 208 Initialization(); 209 else if(ch=='C') 210 Coding(); 211 else if(ch=='D') 212 Decoding(); 213 else if(ch=='P') 214 Print(); 215 else if(ch=='T'){ 216 TreePrinting(myHaffTree+2*n-2,myHaffTree,0); 217 cout<<"此字符形式的哈夫曼树已写入文件treeprint中"<<endl; 218 cout<<endl<<endl; 219 } 220 else if(ch=='E') 221 break; 222 else 223 cout<<"The key is not exsit, please select again !"<<endl; 224 } 225 return 0; 226 }