修改一位叫刘伟高的程序
1// 程序名:HuffmanTree.h
2// 程序功能:哈夫曼树类的头文件(并用其来实现编/译码)
3
4//对应类实现文件: HuffmanTree.cpp
5//对应主程序文件: main.cpp
6
7
8
9#include<iostream>
10#include<fstream>
11#include<string>
12using namespace std;
13struct HuffmanNode //定义哈夫曼树各结点
14{
15 int weight; //存放结点的权值,假设只考虑处理权值为整数的情况
16 int parent; //记录结点父亲位置,-1表示为根结点,否则表示为非根结点
17 int lchild,rchild; //分别存放该结点的左、右孩子的所在单元的编号
18};
19class HuffmanTree //建立哈夫曼树类
20{
21private:
22 HuffmanNode *Node; //哈夫曼树中结点的存储结构
23 char *Info; //用来保存各字符信息
24 int LeafNum; //树中的叶子结点总数
25public:
26 HuffmanTree(); //构造函数
27 ~HuffmanTree(); //析构函数
28 void Initialization(int WeightNum); //初始化函数:根据WeightNum个权值建立一棵哈夫曼树
29 void Encoder(); //编码函数:利用构造好的哈夫曼树对字符进行编码
30 void Decoder(); //译码函数:对二进制串进行译码
31 void Print(); //印文件函数:把已保存好的编码文件显示在屏幕
32 void TreePrinting(); //印哈夫曼树函数:将已在内存中的哈夫曼树以直观的方式显示在终端上
33};
2// 程序功能:哈夫曼树类的头文件(并用其来实现编/译码)
3
4//对应类实现文件: HuffmanTree.cpp
5//对应主程序文件: main.cpp
6
7
8
9#include<iostream>
10#include<fstream>
11#include<string>
12using namespace std;
13struct HuffmanNode //定义哈夫曼树各结点
14{
15 int weight; //存放结点的权值,假设只考虑处理权值为整数的情况
16 int parent; //记录结点父亲位置,-1表示为根结点,否则表示为非根结点
17 int lchild,rchild; //分别存放该结点的左、右孩子的所在单元的编号
18};
19class HuffmanTree //建立哈夫曼树类
20{
21private:
22 HuffmanNode *Node; //哈夫曼树中结点的存储结构
23 char *Info; //用来保存各字符信息
24 int LeafNum; //树中的叶子结点总数
25public:
26 HuffmanTree(); //构造函数
27 ~HuffmanTree(); //析构函数
28 void Initialization(int WeightNum); //初始化函数:根据WeightNum个权值建立一棵哈夫曼树
29 void Encoder(); //编码函数:利用构造好的哈夫曼树对字符进行编码
30 void Decoder(); //译码函数:对二进制串进行译码
31 void Print(); //印文件函数:把已保存好的编码文件显示在屏幕
32 void TreePrinting(); //印哈夫曼树函数:将已在内存中的哈夫曼树以直观的方式显示在终端上
33};
1#include"HuffmanTree.h"
2#include<string>
3using namespace std;
4
5//////////////////////////////////////////////////////////////////////////////
6// 构造函数
7// 函数功能:将结点指针初始化为NULL
8// 函数参数:无
9// 参数返回值:无
10HuffmanTree::HuffmanTree()
11{
12 Node=NULL; //将树结点初始化为空
13 Info=NULL; //将字符数组初始化为空
14 LeafNum=0; //将叶子数初始化为0
15}
16//////////////////////////////////////////////////////////////////////////////
17// 析构函数
18// 函数功能:将所有结点的空间释放
19// 函数参数:无
20// 参数返回值:无
21HuffmanTree::~HuffmanTree()
22{
23 delete[] Node; //释放结点空间
24 delete[] Info; //释放字符存储空间
25}
26//////////////////////////////////////////////////////////////////////////////
27// 初始化函数
28// 函数功能:从终端读入字符集大小n,以及n个字符和n个权值,
29// 建立哈夫曼树,并将它存放在文件hfmTree中.
30// 函数参数:int WeightNum表示代码个数
31// 参数返回值:无
32void HuffmanTree::Initialization(int WeightNum) //初始化
33{
34 int i,j,pos1,pos2,max1,max2; //
35
36 Node=new HuffmanNode[2*WeightNum-1]; //WeightNum权值对应的哈夫曼树中的结点总数为2*WeightNum-1个
37 //Info=new char[2*WeightNum-1];
38 Info=new char[WeightNum];
39 for(i=0;i<WeightNum;i++)
40 {
41 cout<<"请输入第"<<i+1<<"个字符值";
42 getchar(); //丢弃字符'\t'与'\n'
43 Info[i]=getchar(); //输入一个字符,主要是考虑输入空格而采用这种形式的
44 //cin>>Info[i];
45 getchar();
46 cout<<"请输入该字符的权值或频度";
47 cin>>Node[i].weight; //输入权值
48 Node[i].parent=-1; //为根结点
49 Node[i].lchild=-1; //无左孩子
50 Node[i].rchild=-1; //无右孩子
51 }
52
53 for(i=WeightNum;i<2*WeightNum-1;i++) //表示需做WeightNum-1次合并
54 {
55 pos1=-1;
56 pos2=-1; //分别用来存放当前最小值和次小值的所在单元编号
57 max1=32767; //32767为整型数的最大值
58 max2=32767; //分别用来存放当前找到的最小值和次小值
59
60 for(j=0;j<i;j++) //在跟节点中选出权值最小的两个
61 if(Node[j].parent==-1) //是否为根结点
62 if(Node[j].weight<max1) //是否比最小值要小
63 {
64 max2=max1; //原最小值变为次小值
65 max1=Node[j].weight; //存放最小值
66 pos2=pos1; //修改次小值所在单元编号
67 pos1=j; //修改最小值所在单元编号
68 }
69 else
70 if(Node[j].weight<max2) //比原最小值大但比原次小值要小
71 {
72 max2=Node[j].weight; //存放次小值
73 pos2=j; //修改次小值所在的单元编号
74 }
75 //for
76 Node[pos1].parent=i; //修改父亲位置
77 Node[pos2].parent=i;
78 Node[i].lchild=pos1; //修改儿子位置
79 Node[i].rchild=pos2;
80 Node[i].parent=-1; //表示新结点应该是根结点
81 Node[i].weight=Node[pos1].weight+Node[pos2].weight;
82 } //for
83 LeafNum=WeightNum;
84
85
86 char ch;
87 cout<<"是否要替换原来文件(Y/N):";
88 cin>>ch;
89 if(ch=='y'||ch=='Y')
90 {
91 ofstream fop; //以二进制方式打开hfmTree.dat文件,并当重新运行时覆盖原文件
92 fop.open("hfmTree.dat",ios::out|ios::binary|ios::trunc);
93 if(fop.fail()) //文件打开失败
94 cout<<"文件打开失败!\n";
95 fop.write((char*)&WeightNum,sizeof(WeightNum)); //写入WeightNum
96 for(i=0;i<WeightNum;i++) //把各字符信息写入文件
97 {
98 fop.write((char*)&Info[i],sizeof(Info[i]));
99 flush(cout);
100 }
101 for(i=0;i<2*WeightNum-1;i++) //把个节点内容写入文件
102 {
103 fop.write((char*)&Node[i],sizeof(Node[i]));
104 flush(cout);
105 }
106 fop.close(); //关闭文件
107 }
108 cout<<"哈夫曼树已构造完成。\n";
109}//Initialization
110
111//////////////////////////////////////////////////////////////////////////////
112// 编码函数
113// 函数功能:利用已建立好的哈夫曼树(如不在内存,则从文件hfmTree中读入),
114// 对文件ToBeTran中的正文进行编码,然后将结果代码存(传输)到文件CodeFile中.
115// 函数参数:无
116// 参数返回值:无
117void HuffmanTree::Encoder()
118{
119 if(Node==NULL) //哈夫曼树不在内存,从文件hfmTree中读入
120 {
121 ifstream fip; //以二进制方式打开hfmTree.dat文件
122 fip.open("hfmTree.dat",ios::binary|ios::in);
123 if(fip.fail()) //文件打开失败
124 {
125 cout<<"文件打开失败!\n";
126 return; //结束本函数
127 }
128 fip.read((char*)&LeafNum,sizeof(LeafNum)); //读取叶子数
129 Info=new char[LeafNum];
130 Node=new HuffmanNode[2*LeafNum-1];
131 for(int i=0;i<LeafNum;i++) //读取字符信息
132 fip.read((char*)&Info[i],sizeof(Info[i]));
133 for(i=0;i<2*LeafNum-1;i++) //读取结点信息
134 fip.read((char*)&Node[i],sizeof(Node[i]));
135 }
136
137 char *Tree; //用于存储需编码内容
138 int i=0,num;
139 char Choose; //让用户选择读取文件或重新输入需编码内容
140 cout<<"你要从文件中读取内容(1),还是重新输入(2):";
141 cin>>Choose;
142 if(Choose=='1') //读取文件ToBeTran.txt
143 {
144 ifstream fip1("ToBeTran.txt");
145 if(fip1.fail()) //文件不存在
146 {
147 cout<<"文件打开失败!\n";
148 return; //结束本函数
149 }
150 char ch;
151 int k=0;
152 while(fip1.get(ch))
153 {
154 k++; //计算CodeFile中代码长度
155 }
156 fip1.close();
157
158 Tree=new char[k+1];
159 ifstream fip2("ToBeTran.txt");
160
161 k=0;
162 while(fip2.get(ch))
163 {
164 Tree[k]=ch; //读取文件内容,并存到Tree中
165 k++;
166 }
167 fip2.close();
168 Tree[k]='\0'; //结束标志
169 cout<<"需编码内容为:";
170 cout<<Tree<<endl;
171 }//if(Choose=='1')
172
173 else //Choose!='1',重新输入
174 {
175 string tree; //用于输入需编码内容,由于string类对象可以输入任意长度,
176 //所以先利用这个对象输入,再转存在Tree中
177
178 cin.ignore();
179 cout<<"请输入需要编码的内容(可输入任意长,结束时请按2下回车):\n";
180 getline(cin,tree,'\n'); //输入任意长字符串,
181 //getline以回车('\n')作为结束符,第一次按回车表示字符串结束,第二次按回车才开始输出。
182 while(tree[i]!='\0')
183 i++;
184 num=i; //计算tree长度
185 i=0;
186 Tree=new char[num+1];
187 while(tree[i]!='\0') //将tree中的字符转存到Tree中
188 {
189 Tree[i]=tree[i];
190 i++;
191 }
192 Tree[i]='\0'; //结束标志符
193 }
194
195 ofstream fop("CodeFile.dat",ios::trunc); //存储编码后的代码,并覆盖原文件
196 i=0;
197 int k=0;
198 char *code;
199 code=new char[LeafNum]; //为所产生编码分配容量为LeafNum的存储空间
200 //因为不等长编码中最长的编码一定不会超过要求编码的字符个数
201 while(Tree[k]!='\0') //对每一个字符编码
202 {
203 int j,start=0;
204 for(i=0;i<LeafNum;i++)
205 if(Info[i]==Tree[k]) //求出该文字所在单元的编号
206 break;
207 j=i;
208 while(Node[j].parent!=-1) //结点j非树根
209 {
210 j=Node[j].parent; //非结点j的双亲结点
211 if(Node[j].lchild==i) //是左子树,则生成代码0
212 code[start++]='0';
213 else //是右子树,则生成代码1
214 code[start++]='1';\
215 i=j;
216 }
217 code[start]='\0'; //置串结束符
218
219
220 for(i=0;i<start/2;i++) //对二进制序列进行逆置
221 {
222 j=code[i];
223 code[i]=code[start-i-1];
224 code[start-i-1]=j;
225 }
226 i=0;
227 while(code[i]!='\0') //存储代码
228 {
229 fop<<code[i];
230 i++;
231 }
232 k++;
233 }
234 fop.close();
235 cout<<"已编码!且存到文件CodeFile.dat中!\n\n";
236} //Encode
237
238//////////////////////////////////////////////////////////////////////////////
239// 译码函数
240// 函数功能:利用已建好的哈夫曼树,对传输到达的CodeFile中的数据代码进行译码,
241// 将译码结果存入文件TextFile中.
242// 函数参数:无
243// 参数返回值:无
244void HuffmanTree::Decoder()
245{
246 int i=0,k=0;
247 int j=LeafNum*2-1-1; //表示从根结点开始往下搜索
248 char* BitStr;
249
250 ifstream fip1("CodeFile.dat"); //利用已建好的哈夫曼树将文件CodeFile中的代码进行译码
251 if(fip1.fail()) //文件打开失败,还未编码
252 {
253 cout<< "请先编码!\n";
254 return;
255 }
256 cout<<"经译码,原内容为:";
257 char ch;
258 while(fip1.get(ch))
259 {
260 k++; //计算CodeFile中代码长度
261 }
262 fip1.close();
263
264 BitStr=new char[k+1];
265 ifstream fip2("CodeFile.dat");
266 k=0;
267 while(fip2.get(ch))
268 {
269 BitStr[k]=ch; //读取文件内容
270 k++;
271 }
272 fip2.close();
273 BitStr[k]='\0'; //结束标志符
274 if(Node==NULL) //还未建哈夫曼树
275 {
276 cout<<"请先编码!\n";
277 return;
278 }
279 ofstream fop("TextFile.dat"); //将字符形式的编码文件写入文件CodePrin中
280 while(BitStr[i]!='\0')
281 {
282 if(BitStr[i]=='0')
283 j=Node[j].lchild; //往左走
284 else
285 j=Node[j].rchild; //往右走
286 if(Node[j].rchild==-1) //到达叶子结点
287 {
288 cout<<Info[j]; //输出叶子结点对应的字符
289 j=LeafNum*2-1-1; //表示重新从根结点开始往下搜索
290 fop<<Info[j]; //存入文件
291 }//if、
292 i++;
293 }//while
294 fop.close();
295
296 cout<<"\n译码成功且已存到文件TextFile.dat中!\n\n";
297}//Decoder
298//////////////////////////////////////////////////////////////////////////////
299// 印文件代码函数
300// 函数功能:将文件CodeFile以紧凑格式显示在终端上,
301// 每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。
302// 函数参数:无
303// 参数返回值:无
304void HuffmanTree::Print()
305{
306 char ch;
307 int i=1;
308 ifstream fip("CodeFile.dat"); //读取文件
309 ofstream fop("CodePrin.dat"); //存储文件
310 if(fip.fail())
311 {
312 cout<<"没有文件,请先编码!\n";
313
314 return;
315 }
316 while(fip.get(ch))
317 {
318 cout<<ch; //读取文件内容
319 fop<<ch; //存到文件中
320 if(i==50) //每行输出50个字符
321 {
322 cout<<endl;
323 i=0;
324 }
325 i++;
326 }
327 cout<<endl;
328 fip.close(); //关闭CodeFile.dat文件
329 fop.close(); //关闭CodePrin.dat文件
330}
331//////////////////////////////////////////////////////////////////////////////
332// 印哈夫曼树函数
333// 函数功能:将已在内存中的哈夫曼树以直观的方式(树或凹入表的形式)显示在终端上,
334// 同时将此字符形式的哈夫曼树写入文件TreePrint中。
335// 函数参数:无
336// 参数返回值:无
337void HuffmanTree::TreePrinting()
338{
339 if(Node==NULL) //未建立哈夫曼树
340 {
341 cout<<"请先建立哈夫曼树!\n";
342 return;
343 }
344 int i;
345 int j=0,k=LeafNum-1;
346 string *HC;
347 HC=new string[LeafNum]; //定义存储Huffman编码字符串数组
348 for (i=0;i<LeafNum;i++)
349 {
350 char *temp=new char[100]; //实验目的,本处没有求二叉树的深度,而采用固定长度的数组存储Huffman中间编码
351 int k=100;
352 int m=i;
353L1:if (Node[m].parent!=-1) //自定义跳转标签
354 {
355 if (Node[Node[m].parent].lchild==m)
356 {
357 temp[--k]='1';
358 }
359 else
360 {
361 temp[--k]='0';
362 }
363 m=Node[m].parent;
364 goto L1; //跳转到指定的标签L1
365 }
366 else
367 {
368 int n;
369 for (n=k;n<100;n++)
370 {
371 HC[i]=HC[i]+temp[n];
372 }
373 }
374 cout<<i+1<<"号字符的编码为:"<<HC[i]<<"\n"; //输出Huffman编码
375 }
376}
377
2#include<string>
3using namespace std;
4
5//////////////////////////////////////////////////////////////////////////////
6// 构造函数
7// 函数功能:将结点指针初始化为NULL
8// 函数参数:无
9// 参数返回值:无
10HuffmanTree::HuffmanTree()
11{
12 Node=NULL; //将树结点初始化为空
13 Info=NULL; //将字符数组初始化为空
14 LeafNum=0; //将叶子数初始化为0
15}
16//////////////////////////////////////////////////////////////////////////////
17// 析构函数
18// 函数功能:将所有结点的空间释放
19// 函数参数:无
20// 参数返回值:无
21HuffmanTree::~HuffmanTree()
22{
23 delete[] Node; //释放结点空间
24 delete[] Info; //释放字符存储空间
25}
26//////////////////////////////////////////////////////////////////////////////
27// 初始化函数
28// 函数功能:从终端读入字符集大小n,以及n个字符和n个权值,
29// 建立哈夫曼树,并将它存放在文件hfmTree中.
30// 函数参数:int WeightNum表示代码个数
31// 参数返回值:无
32void HuffmanTree::Initialization(int WeightNum) //初始化
33{
34 int i,j,pos1,pos2,max1,max2; //
35
36 Node=new HuffmanNode[2*WeightNum-1]; //WeightNum权值对应的哈夫曼树中的结点总数为2*WeightNum-1个
37 //Info=new char[2*WeightNum-1];
38 Info=new char[WeightNum];
39 for(i=0;i<WeightNum;i++)
40 {
41 cout<<"请输入第"<<i+1<<"个字符值";
42 getchar(); //丢弃字符'\t'与'\n'
43 Info[i]=getchar(); //输入一个字符,主要是考虑输入空格而采用这种形式的
44 //cin>>Info[i];
45 getchar();
46 cout<<"请输入该字符的权值或频度";
47 cin>>Node[i].weight; //输入权值
48 Node[i].parent=-1; //为根结点
49 Node[i].lchild=-1; //无左孩子
50 Node[i].rchild=-1; //无右孩子
51 }
52
53 for(i=WeightNum;i<2*WeightNum-1;i++) //表示需做WeightNum-1次合并
54 {
55 pos1=-1;
56 pos2=-1; //分别用来存放当前最小值和次小值的所在单元编号
57 max1=32767; //32767为整型数的最大值
58 max2=32767; //分别用来存放当前找到的最小值和次小值
59
60 for(j=0;j<i;j++) //在跟节点中选出权值最小的两个
61 if(Node[j].parent==-1) //是否为根结点
62 if(Node[j].weight<max1) //是否比最小值要小
63 {
64 max2=max1; //原最小值变为次小值
65 max1=Node[j].weight; //存放最小值
66 pos2=pos1; //修改次小值所在单元编号
67 pos1=j; //修改最小值所在单元编号
68 }
69 else
70 if(Node[j].weight<max2) //比原最小值大但比原次小值要小
71 {
72 max2=Node[j].weight; //存放次小值
73 pos2=j; //修改次小值所在的单元编号
74 }
75 //for
76 Node[pos1].parent=i; //修改父亲位置
77 Node[pos2].parent=i;
78 Node[i].lchild=pos1; //修改儿子位置
79 Node[i].rchild=pos2;
80 Node[i].parent=-1; //表示新结点应该是根结点
81 Node[i].weight=Node[pos1].weight+Node[pos2].weight;
82 } //for
83 LeafNum=WeightNum;
84
85
86 char ch;
87 cout<<"是否要替换原来文件(Y/N):";
88 cin>>ch;
89 if(ch=='y'||ch=='Y')
90 {
91 ofstream fop; //以二进制方式打开hfmTree.dat文件,并当重新运行时覆盖原文件
92 fop.open("hfmTree.dat",ios::out|ios::binary|ios::trunc);
93 if(fop.fail()) //文件打开失败
94 cout<<"文件打开失败!\n";
95 fop.write((char*)&WeightNum,sizeof(WeightNum)); //写入WeightNum
96 for(i=0;i<WeightNum;i++) //把各字符信息写入文件
97 {
98 fop.write((char*)&Info[i],sizeof(Info[i]));
99 flush(cout);
100 }
101 for(i=0;i<2*WeightNum-1;i++) //把个节点内容写入文件
102 {
103 fop.write((char*)&Node[i],sizeof(Node[i]));
104 flush(cout);
105 }
106 fop.close(); //关闭文件
107 }
108 cout<<"哈夫曼树已构造完成。\n";
109}//Initialization
110
111//////////////////////////////////////////////////////////////////////////////
112// 编码函数
113// 函数功能:利用已建立好的哈夫曼树(如不在内存,则从文件hfmTree中读入),
114// 对文件ToBeTran中的正文进行编码,然后将结果代码存(传输)到文件CodeFile中.
115// 函数参数:无
116// 参数返回值:无
117void HuffmanTree::Encoder()
118{
119 if(Node==NULL) //哈夫曼树不在内存,从文件hfmTree中读入
120 {
121 ifstream fip; //以二进制方式打开hfmTree.dat文件
122 fip.open("hfmTree.dat",ios::binary|ios::in);
123 if(fip.fail()) //文件打开失败
124 {
125 cout<<"文件打开失败!\n";
126 return; //结束本函数
127 }
128 fip.read((char*)&LeafNum,sizeof(LeafNum)); //读取叶子数
129 Info=new char[LeafNum];
130 Node=new HuffmanNode[2*LeafNum-1];
131 for(int i=0;i<LeafNum;i++) //读取字符信息
132 fip.read((char*)&Info[i],sizeof(Info[i]));
133 for(i=0;i<2*LeafNum-1;i++) //读取结点信息
134 fip.read((char*)&Node[i],sizeof(Node[i]));
135 }
136
137 char *Tree; //用于存储需编码内容
138 int i=0,num;
139 char Choose; //让用户选择读取文件或重新输入需编码内容
140 cout<<"你要从文件中读取内容(1),还是重新输入(2):";
141 cin>>Choose;
142 if(Choose=='1') //读取文件ToBeTran.txt
143 {
144 ifstream fip1("ToBeTran.txt");
145 if(fip1.fail()) //文件不存在
146 {
147 cout<<"文件打开失败!\n";
148 return; //结束本函数
149 }
150 char ch;
151 int k=0;
152 while(fip1.get(ch))
153 {
154 k++; //计算CodeFile中代码长度
155 }
156 fip1.close();
157
158 Tree=new char[k+1];
159 ifstream fip2("ToBeTran.txt");
160
161 k=0;
162 while(fip2.get(ch))
163 {
164 Tree[k]=ch; //读取文件内容,并存到Tree中
165 k++;
166 }
167 fip2.close();
168 Tree[k]='\0'; //结束标志
169 cout<<"需编码内容为:";
170 cout<<Tree<<endl;
171 }//if(Choose=='1')
172
173 else //Choose!='1',重新输入
174 {
175 string tree; //用于输入需编码内容,由于string类对象可以输入任意长度,
176 //所以先利用这个对象输入,再转存在Tree中
177
178 cin.ignore();
179 cout<<"请输入需要编码的内容(可输入任意长,结束时请按2下回车):\n";
180 getline(cin,tree,'\n'); //输入任意长字符串,
181 //getline以回车('\n')作为结束符,第一次按回车表示字符串结束,第二次按回车才开始输出。
182 while(tree[i]!='\0')
183 i++;
184 num=i; //计算tree长度
185 i=0;
186 Tree=new char[num+1];
187 while(tree[i]!='\0') //将tree中的字符转存到Tree中
188 {
189 Tree[i]=tree[i];
190 i++;
191 }
192 Tree[i]='\0'; //结束标志符
193 }
194
195 ofstream fop("CodeFile.dat",ios::trunc); //存储编码后的代码,并覆盖原文件
196 i=0;
197 int k=0;
198 char *code;
199 code=new char[LeafNum]; //为所产生编码分配容量为LeafNum的存储空间
200 //因为不等长编码中最长的编码一定不会超过要求编码的字符个数
201 while(Tree[k]!='\0') //对每一个字符编码
202 {
203 int j,start=0;
204 for(i=0;i<LeafNum;i++)
205 if(Info[i]==Tree[k]) //求出该文字所在单元的编号
206 break;
207 j=i;
208 while(Node[j].parent!=-1) //结点j非树根
209 {
210 j=Node[j].parent; //非结点j的双亲结点
211 if(Node[j].lchild==i) //是左子树,则生成代码0
212 code[start++]='0';
213 else //是右子树,则生成代码1
214 code[start++]='1';\
215 i=j;
216 }
217 code[start]='\0'; //置串结束符
218
219
220 for(i=0;i<start/2;i++) //对二进制序列进行逆置
221 {
222 j=code[i];
223 code[i]=code[start-i-1];
224 code[start-i-1]=j;
225 }
226 i=0;
227 while(code[i]!='\0') //存储代码
228 {
229 fop<<code[i];
230 i++;
231 }
232 k++;
233 }
234 fop.close();
235 cout<<"已编码!且存到文件CodeFile.dat中!\n\n";
236} //Encode
237
238//////////////////////////////////////////////////////////////////////////////
239// 译码函数
240// 函数功能:利用已建好的哈夫曼树,对传输到达的CodeFile中的数据代码进行译码,
241// 将译码结果存入文件TextFile中.
242// 函数参数:无
243// 参数返回值:无
244void HuffmanTree::Decoder()
245{
246 int i=0,k=0;
247 int j=LeafNum*2-1-1; //表示从根结点开始往下搜索
248 char* BitStr;
249
250 ifstream fip1("CodeFile.dat"); //利用已建好的哈夫曼树将文件CodeFile中的代码进行译码
251 if(fip1.fail()) //文件打开失败,还未编码
252 {
253 cout<< "请先编码!\n";
254 return;
255 }
256 cout<<"经译码,原内容为:";
257 char ch;
258 while(fip1.get(ch))
259 {
260 k++; //计算CodeFile中代码长度
261 }
262 fip1.close();
263
264 BitStr=new char[k+1];
265 ifstream fip2("CodeFile.dat");
266 k=0;
267 while(fip2.get(ch))
268 {
269 BitStr[k]=ch; //读取文件内容
270 k++;
271 }
272 fip2.close();
273 BitStr[k]='\0'; //结束标志符
274 if(Node==NULL) //还未建哈夫曼树
275 {
276 cout<<"请先编码!\n";
277 return;
278 }
279 ofstream fop("TextFile.dat"); //将字符形式的编码文件写入文件CodePrin中
280 while(BitStr[i]!='\0')
281 {
282 if(BitStr[i]=='0')
283 j=Node[j].lchild; //往左走
284 else
285 j=Node[j].rchild; //往右走
286 if(Node[j].rchild==-1) //到达叶子结点
287 {
288 cout<<Info[j]; //输出叶子结点对应的字符
289 j=LeafNum*2-1-1; //表示重新从根结点开始往下搜索
290 fop<<Info[j]; //存入文件
291 }//if、
292 i++;
293 }//while
294 fop.close();
295
296 cout<<"\n译码成功且已存到文件TextFile.dat中!\n\n";
297}//Decoder
298//////////////////////////////////////////////////////////////////////////////
299// 印文件代码函数
300// 函数功能:将文件CodeFile以紧凑格式显示在终端上,
301// 每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。
302// 函数参数:无
303// 参数返回值:无
304void HuffmanTree::Print()
305{
306 char ch;
307 int i=1;
308 ifstream fip("CodeFile.dat"); //读取文件
309 ofstream fop("CodePrin.dat"); //存储文件
310 if(fip.fail())
311 {
312 cout<<"没有文件,请先编码!\n";
313
314 return;
315 }
316 while(fip.get(ch))
317 {
318 cout<<ch; //读取文件内容
319 fop<<ch; //存到文件中
320 if(i==50) //每行输出50个字符
321 {
322 cout<<endl;
323 i=0;
324 }
325 i++;
326 }
327 cout<<endl;
328 fip.close(); //关闭CodeFile.dat文件
329 fop.close(); //关闭CodePrin.dat文件
330}
331//////////////////////////////////////////////////////////////////////////////
332// 印哈夫曼树函数
333// 函数功能:将已在内存中的哈夫曼树以直观的方式(树或凹入表的形式)显示在终端上,
334// 同时将此字符形式的哈夫曼树写入文件TreePrint中。
335// 函数参数:无
336// 参数返回值:无
337void HuffmanTree::TreePrinting()
338{
339 if(Node==NULL) //未建立哈夫曼树
340 {
341 cout<<"请先建立哈夫曼树!\n";
342 return;
343 }
344 int i;
345 int j=0,k=LeafNum-1;
346 string *HC;
347 HC=new string[LeafNum]; //定义存储Huffman编码字符串数组
348 for (i=0;i<LeafNum;i++)
349 {
350 char *temp=new char[100]; //实验目的,本处没有求二叉树的深度,而采用固定长度的数组存储Huffman中间编码
351 int k=100;
352 int m=i;
353L1:if (Node[m].parent!=-1) //自定义跳转标签
354 {
355 if (Node[Node[m].parent].lchild==m)
356 {
357 temp[--k]='1';
358 }
359 else
360 {
361 temp[--k]='0';
362 }
363 m=Node[m].parent;
364 goto L1; //跳转到指定的标签L1
365 }
366 else
367 {
368 int n;
369 for (n=k;n<100;n++)
370 {
371 HC[i]=HC[i]+temp[n];
372 }
373 }
374 cout<<i+1<<"号字符的编码为:"<<HC[i]<<"\n"; //输出Huffman编码
375 }
376}
377
1// 程序名:main.cpp
2// 程序功能:主函数源文件
3
4#include"HuffmanTree.h"
5#include<string.h>
6#include<stdlib.h>
7
8//////////////////////////////////////////////////////////////////////////////
9// 主函数
10//参数返回值:无
11
12int main()
13{
14
15 cout<<"(I) 初始化;\n";
16 cout<<"(E) 编码;\n";
17 cout<<"(D) 译码;\n";
18 cout<<"(P) 印代码文件;\n";
19 cout<<"(T) 印哈夫曼树\n";
20 cout<<"(Q) 退出\n\n";
21 HuffmanTree huftree; //定义哈夫曼树对象
22 int weight;
23 char Choose;
24 while(1)
25 {
26 cout<<"请从清单中选择一个操作(不区分大小写):";
27 cin>>Choose;
28 switch(Choose)
29 {
30 case 'I':
31 case 'i':
32 cout<<"请输入编码长度:";
33 cin>>weight;
34 huftree.Initialization(weight); //初始化哈夫曼树
35 break;
36 case 'E':
37 case 'e':
38 huftree.Encoder();
39 break;
40 case 'D':
41 case 'd':
42 huftree.Decoder();
43 break;
44 case 'P':
45 case 'p':
46 huftree.Print();
47 break;
48 case 'T':
49 case 't':
50 huftree.TreePrinting();
51 break;
52 case 'Q':
53 case 'q':
54 cout<<"\n ***********感谢使用本系统!***********\n\n";
55 system("pause"); //暂停运行
56 return 0;
57 }
58 cout<<"(I) 初始化;\n";
59 cout<<"(E) 编码;\n";
60 cout<<"(D) 译码;\n";
61 cout<<"(P) 印代码文件;\n";
62 cout<<"(T) 印哈夫曼树\n";
63 cout<<"(Q) 退出\n\n";
64 }
65}
66
2// 程序功能:主函数源文件
3
4#include"HuffmanTree.h"
5#include<string.h>
6#include<stdlib.h>
7
8//////////////////////////////////////////////////////////////////////////////
9// 主函数
10//参数返回值:无
11
12int main()
13{
14
15 cout<<"(I) 初始化;\n";
16 cout<<"(E) 编码;\n";
17 cout<<"(D) 译码;\n";
18 cout<<"(P) 印代码文件;\n";
19 cout<<"(T) 印哈夫曼树\n";
20 cout<<"(Q) 退出\n\n";
21 HuffmanTree huftree; //定义哈夫曼树对象
22 int weight;
23 char Choose;
24 while(1)
25 {
26 cout<<"请从清单中选择一个操作(不区分大小写):";
27 cin>>Choose;
28 switch(Choose)
29 {
30 case 'I':
31 case 'i':
32 cout<<"请输入编码长度:";
33 cin>>weight;
34 huftree.Initialization(weight); //初始化哈夫曼树
35 break;
36 case 'E':
37 case 'e':
38 huftree.Encoder();
39 break;
40 case 'D':
41 case 'd':
42 huftree.Decoder();
43 break;
44 case 'P':
45 case 'p':
46 huftree.Print();
47 break;
48 case 'T':
49 case 't':
50 huftree.TreePrinting();
51 break;
52 case 'Q':
53 case 'q':
54 cout<<"\n ***********感谢使用本系统!***********\n\n";
55 system("pause"); //暂停运行
56 return 0;
57 }
58 cout<<"(I) 初始化;\n";
59 cout<<"(E) 编码;\n";
60 cout<<"(D) 译码;\n";
61 cout<<"(P) 印代码文件;\n";
62 cout<<"(T) 印哈夫曼树\n";
63 cout<<"(Q) 退出\n\n";
64 }
65}
66