[DataStructure]HuffMan编码与译码
HuffMan编码与译码
Iris.Catch-22.S`、
一、题目描述:
设字符集为26个英文字母,给出其出现频度。(空格、a~z大小写不敏感)
先建哈夫曼树,再利用此树对报文“This program is my favorite”进行编码和译码。
二、解题报告
1.建立结构
1 /*HuffManTree Node*/ 2 struct HuffManTNode 3 { 4 int Weight;//权重 5 int Par; 6 int LChild; 7 int RChild; 8 }; 9 10 /*HuffMan Code*/ 11 struct HuffCode 12 { 13 int Codes[MAXLEN]; //HuffMan 编码 14 int Length; //HuffMan 编码长度 15 char Data;//字母空格 16 }; 17 18 19 /*字母出现的频数*/ 20 int a[MAXNUM] = 21 {186,64,13,22,32,103,21,15,47,57,1,5,32,20,57,63,15,1,48,51,80,23,8,18,1,16,1}; 22 23 char Letter['z'];//存储字符位置 24 25 26 /*Declare HuffManTree Node&&HuffMan Code*/ 27 28 HuffManTNode *HuffManTN = new HuffManTNode[2*MAXNUM-1]; 29 HuffCode *HuffManTC = new HuffCode[MAXNUM]; 30 31 32 /*初始化String*/ 33 string Words="This program is my favorite";
2.主程序框架
1 int main() 2 { 3 CopyRight(); 4 5 /*HuffMan Tree构建及HuffMan Code生成*/ 6 Huffman(a,MAXNUM,HuffManTN,HuffManTC); 7 8 /*HuffManCode输出*/ 9 OutputHuffManCode(); 10 11 /*译码解码任务分配过程*/ 12 TaskMgr(); 13 14 return 0; 15 }
3.HuffManTree建立及HuffManCode形成
1 void Huffman(int Weight[], int n, HuffManTNode HuffManTN[], HuffCode HuffManTC[]) //出现频次/字符个数/HMTree结点/HM编码 2 { 3 /*Flag字符标识*/ 4 char ch; 5 char Flag[n]; 6 Flag[0]=' '; 7 for (int i=1,ch='a';i<=n;++i,++ch) 8 Flag[i]=ch; 9 10 /* Create Huffman Node ,Step 1*/ 11 for(int i=0; i<2*n-1;++i) 12 { 13 if (i<n) 14 HuffManTN[i].Weight=Weight[i]; 15 else 16 HuffManTN[i].Weight=0; 17 HuffManTN[i].Par=0; 18 HuffManTN[i].LChild=HuffManTN[i].RChild=-1; 19 } 20 21 /* Create Huffman Node ,Step 2*/ 22 int l,r; //l,r分别代表新建的节点所用到的两个结点 23 int min1,min2; //存储每次选择的最小的两个Weight 24 for(int i=0;i<n-1;++i) 25 { 26 min1=min2=Maxlongint; 27 l=r=0; 28 for(int j=0;j<n+i;j++) 29 { 30 if(HuffManTN[j].Weight < min1 && HuffManTN[j].Par==0) 31 { 32 min2= min1; 33 min1= HuffManTN[j].Weight; 34 r=l; 35 l=j; 36 } 37 else if(HuffManTN[j].Weight < min2 && HuffManTN[j].Par==0) 38 { 39 min2=HuffManTN[j].Weight; 40 r=j; 41 } 42 } 43 44 ///Create a new HuffMan Node 45 HuffManTN[n+i].Weight=min1+min2; 46 HuffManTN[l].Par=n+i; 47 HuffManTN[r].Par=n+i; 48 HuffManTN[n+i].LChild=l; 49 HuffManTN[n+i].RChild=r; 50 } 51 52 int Temp[MAXLEN]; ///在此逆序存储Huffman编码 53 int j; 54 for(int i=0;i<n;++i) 55 { 56 j=0; 57 int Child=i; 58 int Par=HuffManTN[i].Par; 59 while(HuffManTN[Child].Par != 0) ///逆序存储 60 { 61 if(HuffManTN[Par].LChild == Child) Temp[j++] = 0; 62 else Temp[j++] = 1; 63 Child=Par; 64 Par=HuffManTN[Par].Par; 65 } 66 67 ///正序存储到HuffCode中 68 int k=0; 69 HuffManTC[i].Length=j; 70 HuffManTC[i].Data=Flag[i]; 71 while(j) 72 HuffManTC[i].Codes[k++]=Temp[--j]; 73 ///仔细想想++ --的意义…… 74 } 75 }
4.HuffMan编码的输出
1 void OutputHuffManCode() 2 { 3 char ch1,ch2; 4 /*由于ASCII码特殊性,特殊输出空格……*/ 5 int i=0; 6 ch1=’ ‘; 7 Letter[ch1]=i; 8 cout<<"Letter:"<<HuffManTC[i].Data<<",Code="; 9 for(int j=0;j<HuffManTC[i].Length;++j) 10 cout<<HuffManTC[i].Codes[j]; 11 cout<<endl; 12 /*输出a~z*/ 13 for(int i=1,ch1='a',ch2='A'; i<MAXNUM; ++i,++ch1,++ch2) 14 { 15 Letter[ch1]=Letter[ch2]=i;///此处为下文译码便捷性做出 16 ///即找到i对应a-z及A-Z 17 cout<<"Letter:"<<HuffManTC[i].Data<<",Code="; 18 for(int j=0;j<HuffManTC[i].Length;++j) 19 cout<<HuffManTC[i].Codes[j]; 20 cout<<endl; 21 } 22 }
5.解码译码任务模块
1 void TaskMgr() 2 { 3 cout<<"请问您是要编码还是解码?编码输入A,解码输入B"<<endl; 4 string Flag;//如果用Char标识的话字符串在getline读入时会丢失首字母 5 getline(cin,Flag); 6 while (Flag!="A" && Flag!="B") 7 { 8 cout<<"输入有误,请重新输入!"<<endl; 9 getline(cin,Flag); 10 } 11 if (Flag=="A") 12 { 13 Making_InputData(); 14 Making_OutputData(); 15 } 16 if (Flag=="B") 17 { 18 De_InputData(); 19 } 20 }
6.译码模块一读入模块
1 ///因为有空格所以不能cin 2 void Making_InputData() 3 { 4 cout<<"请输入要编码的语句"<<endl; 5 char flag; 6 cin>>flag; 7 getline(cin,Words); 8 Words=flag+Words; 9 cout<<"您输入的是:"<<Words<<endl; 10 }
7.译码模块二--输出模块(内嵌译码过程)
1 void Making_OutputData() 2 { 3 for (int i=0;i<Words.size();++i)///逐个字母输出对应编码,可省略 4 { 5 cout<<Words[i]<<"-----------------"; 6 for(int j=0;j<HuffManTC[Letter[Words[i]]].Length;++j) 7 cout<<HuffManTC[Letter[Words[i]]].Codes[j]; 8 cout<<endl; 9 } 10 for (int i=0;i<Words.size();++i)///完整编码 11 { 12 for(int j=0;j<HuffManTC[Letter[Words[i]]].Length;++j) 13 cout<<HuffManTC[Letter[Words[i]]].Codes[j]; 14 } 15 cout<<endl; 16 }
8.解码模块一-读入模块
1 void De_InputData() 2 { 3 cout<<"请输入要译码的语句"<<endl; 4 cin>>Words; 5 cout<<"您输入的是:"<<Words<<endl; 6 DeCoding(Words); cout<<endl; 7 }
9.解码模块二-解码过程(内嵌输出)
1 void DeCoding(string Words) 2 { 3 int Flag,Tmp; 4 for (int i=0;i<Words.size();) 5 { Tmp=i; 6 for (int j=0;j<MAXNUM;++j) 7 { 8 Flag=1; 9 for(int k=0;k<HuffManTC[j].Length;++k) 10 { 11 if (HuffManTC[j].Codes[k]==Words[Tmp]) ++Tmp; 12 else 13 { 14 Flag=-1; 15 Tmp=i; 16 break; 17 } 18 } 19 if (Flag==1) 20 { i=Tmp; 21 if (j==0) cout<<' '; 22 else cout<<char('a'+j-1); 23 break; 24 } 25 else if (Flag==-1 && j==MAXNUM-1) return;//此情形说明输入有误 26 } //遍历一遍后发现之后无对应字母 27 } 28 }
10.完整代码
1 /* 2 By 3 Iris.Catch-22.S、` 4 Dept. of Mathematics, 5 School of Science, 6 HIT 7 December,2015 8 */ 9 #include<iostream> 10 #include<cstring> 11 using namespace std; 12 void CopyRight() 13 { 14 cout<<"------------By ICS,HIT,2015/12-------------"<<endl; 15 cout<<"-------------HuffmanTree Code--------------"<<endl; 16 cout<<"-----------------Ver 1.0.0-----------------"<<endl; 17 } 18 19 /*#define一些定值*/ 20 #define MAXNUM 27 21 #define MAXLEN 100 //HuffMan编码最大长度 22 #define Maxlongint 2147483647 23 24 /*字母出现的频数,可简单修改程序达到读入频数的目的*/ 25 int a[MAXNUM] 26 ={186,64,13,22,32,103,21,15,47,57,1,5,32,20,57,63,15,1,48,51,80,23,8,18,1,16,1}; 27 28 /*HuffManTree Node*/ 29 struct HuffManTNode 30 { 31 int Weight;//权重 32 int Par; 33 int LChild; 34 int RChild; 35 }; 36 37 /*HuffMan Code*/ 38 struct HuffCode 39 { 40 char Codes[MAXLEN]; //HuffMan 编码 41 int Length; //HuffMan 编码长度 42 char Data; 43 }; 44 char Letter['z']; 45 /*Declare HuffManTree Node&&HuffMan Code*/ 46 HuffManTNode *HuffManTN = new HuffManTNode[2*MAXNUM-1]; 47 HuffCode *HuffManTC = new HuffCode[MAXNUM]; 48 /*HuffMan*/ 49 void Huffman(int Weight[], int n, HuffManTNode HuffManTN[], HuffCode HuffManTC[]) //出现频次/字符个数/HMTree结点/HM编码 50 { 51 /*Flag字符标识*/ 52 char ch; 53 char Flag[n]; 54 Flag[0]=' '; 55 for (int i=1,ch='a';i<=n;++i,++ch) 56 Flag[i]=ch; 57 /* Create Huffman Node ,Step 1*/ 58 for(int i=0; i<2*n-1;++i) 59 { 60 if (i<n) 61 HuffManTN[i].Weight=Weight[i]; 62 else 63 HuffManTN[i].Weight=0; 64 HuffManTN[i].Par=0; 65 HuffManTN[i].LChild=HuffManTN[i].RChild=-1; 66 } 67 /* Create Huffman Node ,Step 2*/ 68 int l,r; //l,r分别代表新建的节点所用到的两个结点 69 int min1,min2; //存储每次选择的最小的两个Weight 70 for(int i=0;i<n-1;++i) 71 { 72 min1=min2=Maxlongint; 73 l=r=0; 74 for(int j=0;j<n+i;j++) 75 { 76 if(HuffManTN[j].Weight < min1 && HuffManTN[j].Par==0) 77 { 78 min2= min1; 79 min1= HuffManTN[j].Weight; 80 r=l; 81 l=j; 82 } 83 else if(HuffManTN[j].Weight < min2 && HuffManTN[j].Par==0) 84 { 85 min2=HuffManTN[j].Weight; 86 r=j; 87 } 88 } 89 ///Create a new Huffman Node 90 HuffManTN[n+i].Weight=min1+min2; 91 HuffManTN[l].Par=n+i; 92 HuffManTN[r].Par=n+i; 93 HuffManTN[n+i].LChild=l; 94 HuffManTN[n+i].RChild=r; 95 } 96 int Temp[MAXLEN]; ///逆序存储HuffMan编码 97 int j; 98 for(int i=0;i<n;++i) 99 { 100 j=0; 101 int Child=i; 102 int Par=HuffManTN[i].Par; 103 while(HuffManTN[Child].Par != 0) ///逆序存储 104 { 105 if(HuffManTN[Par].LChild == Child) Temp[j++] = '0'; 106 else Temp[j++] = '1'; 107 Child=Par; 108 Par=HuffManTN[Par].Par; 109 } 110 ///正序存储到HuffManTC中 111 int k=0; 112 HuffManTC[i].Length=j; 113 HuffManTC[i].Data=Flag[i]; 114 while(j) 115 HuffManTC[i].Codes[k++]=Temp[--j]; 116 } 117 } 118 119 void OutputHuffManCode() 120 { 121 122 char ch1,ch2; 123 int i=0; 124 cout<<"Letter:"<<HuffManTC[i].Data<<",Code="; 125 for(int j=0;j<HuffManTC[i].Length;++j) 126 cout<<HuffManTC[i].Codes[j]; 127 cout<<endl; 128 for(int i=1,ch1='a',ch2='A'; i<MAXNUM; ++i,++ch1,++ch2) 129 { 130 cout<<"Letter:"<<HuffManTC[i].Data<<",Code="; 131 Letter[ch1]=Letter[ch2]=i; 132 for(int j=0;j<HuffManTC[i].Length;++j) 133 cout<<HuffManTC[i].Codes[j]; 134 cout<<endl; 135 } 136 } 137 /*-----------------------编码解码-----------------------*/ 138 string Words="This program is my favorite"; 139 ///1101000101100011111100010001010011000010010101011001011101100011111110010100011111110011101011000001001001001101101010 140 /*编码*/ 141 void Making_InputData() 142 { 143 cout<<"请输入要编码的语句"<<endl; 144 getline(cin,Words); 145 cout<<"您输入的是:"<<Words<<endl; 146 } 147 void Making_OutputData() 148 { 149 for (int i=0;i<Words.size();++i) 150 { 151 cout<<Words[i]<<"-----------------"; 152 for(int j=0;j<HuffManTC[Letter[Words[i]]].Length;++j) 153 cout<<HuffManTC[Letter[Words[i]]].Codes[j]; 154 cout<<endl; 155 } 156 for (int i=0;i<Words.size();++i) 157 { 158 for(int j=0;j<HuffManTC[Letter[Words[i]]].Length;++j) 159 cout<<HuffManTC[Letter[Words[i]]].Codes[j]; 160 } 161 cout<<endl; 162 } 163 /*解码*/ 164 void DeCoding(string Words) 165 { int Flag,Tmp; 166 for (int i=0;i<Words.size();) 167 { Tmp=i; 168 for (int j=0;j<MAXNUM;++j) 169 { Flag=1; 170 for(int k=0;k<HuffManTC[j].Length;++k) 171 { 172 if (HuffManTC[j].Codes[k]==Words[Tmp]) 173 ++Tmp; 174 else 175 { Flag=-1; 176 Tmp=i; 177 break; 178 } 179 } 180 if (Flag==1) 181 { i=Tmp; 182 if (j==0) cout<<' '; 183 else cout<<char('a'+j-1); 184 break; 185 } 186 else if (Flag==-1 && j==MAXNUM-1) return;//此情形说明输入有误 187 } //遍历一遍后发现之后无对应字母 188 } 189 } 190 } 191 void De_InputData() 192 { 193 cout<<"请输入要译码的语句"<<endl; 194 cin>>Words; 195 cout<<"您输入的是:"<<Words<<endl; 196 DeCoding(Words); 197 } 198 void TaskMgr() 199 { 200 cout<<"请问您是要编码还是解码?编码输入A,解码输入B"<<endl; 201 string Flag; 202 getline(cin,Flag); 203 while (Flag!="A" && Flag!="B") 204 { 205 cout<<"输入有误,请重新输入!"<<endl; 206 getline(cin,Flag); 207 } 208 if (Flag=="A") 209 { 210 Making_InputData(); 211 Making_OutputData(); 212 } 213 if (Flag=="B") 214 { 215 De_InputData(); 216 } 217 int main() 218 { 219 CopyRight(); 220 Huffman(a,MAXNUM,HuffManTN,HuffManTC); 221 OutputHuffManCode(); 222 TaskMgr(); 223 return 0; 224 }
P.S.
呃、 DataStructure Rank1了、不过也理所当然(hhhhh)
然而发现写代码都不知道要写int main的也90+我直接呵呵哒了(23333333)
算了、你们开心就好。
想起Matrix67神犇大概的一句话,“正因为没在数学专业学习,我才能不以考试为目的地学习任何自己想学的数学知识,才能对数学有如此浓厚的兴趣”
嗯,改个主语233
在我系除了还有个数据库数据挖掘外基本不学Coding了吧
好吧、你们开心就好
有发现什么bug的话说一声……反正我这三个作业是满分(然而这并不能说明任何问题呵呵哒)