修改一位叫刘伟高的程序
1
// 程序名:HuffmanTree.h
2
// 程序功能:哈夫曼树类的头文件(并用其来实现编/译码)
3
4
//对应类实现文件: HuffmanTree.cpp
5
//对应主程序文件: main.cpp
6
7
8
9
#include<iostream>
10
#include<fstream>
11
#include<string>
12
using namespace std;
13
struct HuffmanNode //定义哈夫曼树各结点
14
{
15
int weight; //存放结点的权值,假设只考虑处理权值为整数的情况
16
int parent; //记录结点父亲位置,-1表示为根结点,否则表示为非根结点
17
int lchild,rchild; //分别存放该结点的左、右孩子的所在单元的编号
18
};
19
class HuffmanTree //建立哈夫曼树类
20
{
21
private:
22
HuffmanNode *Node; //哈夫曼树中结点的存储结构
23
char *Info; //用来保存各字符信息
24
int LeafNum; //树中的叶子结点总数
25
public:
26
HuffmanTree(); //构造函数
27
~HuffmanTree(); //析构函数
28
void Initialization(int WeightNum); //初始化函数:根据WeightNum个权值建立一棵哈夫曼树
29
void Encoder(); //编码函数:利用构造好的哈夫曼树对字符进行编码
30
void Decoder(); //译码函数:对二进制串进行译码
31
void Print(); //印文件函数:把已保存好的编码文件显示在屏幕
32
void TreePrinting(); //印哈夫曼树函数:将已在内存中的哈夫曼树以直观的方式显示在终端上
33
};
// 程序名:HuffmanTree.h2
// 程序功能:哈夫曼树类的头文件(并用其来实现编/译码)3

4
//对应类实现文件: HuffmanTree.cpp5
//对应主程序文件: main.cpp6

7
8

9
#include<iostream>10
#include<fstream>11
#include<string>12
using namespace std;13
struct HuffmanNode //定义哈夫曼树各结点14
{15
int weight; //存放结点的权值,假设只考虑处理权值为整数的情况16
int parent; //记录结点父亲位置,-1表示为根结点,否则表示为非根结点17
int lchild,rchild; //分别存放该结点的左、右孩子的所在单元的编号18
};19
class HuffmanTree //建立哈夫曼树类20
{21
private:22
HuffmanNode *Node; //哈夫曼树中结点的存储结构23
char *Info; //用来保存各字符信息24
int LeafNum; //树中的叶子结点总数25
public: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>
3
using namespace std;
4
5
//////////////////////////////////////////////////////////////////////////////
6
// 构造函数
7
// 函数功能:将结点指针初始化为NULL
8
// 函数参数:无
9
// 参数返回值:无
10
HuffmanTree::HuffmanTree()
11
{
12
Node=NULL; //将树结点初始化为空
13
Info=NULL; //将字符数组初始化为空
14
LeafNum=0; //将叶子数初始化为0
15
}
16
//////////////////////////////////////////////////////////////////////////////
17
// 析构函数
18
// 函数功能:将所有结点的空间释放
19
// 函数参数:无
20
// 参数返回值:无
21
HuffmanTree::~HuffmanTree()
22
{
23
delete[] Node; //释放结点空间
24
delete[] Info; //释放字符存储空间
25
}
26
//////////////////////////////////////////////////////////////////////////////
27
// 初始化函数
28
// 函数功能:从终端读入字符集大小n,以及n个字符和n个权值,
29
// 建立哈夫曼树,并将它存放在文件hfmTree中.
30
// 函数参数:int WeightNum表示代码个数
31
// 参数返回值:无
32
void 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
// 参数返回值:无
117
void 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
// 参数返回值:无
244
void 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
// 参数返回值:无
304
void 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
// 参数返回值:无
337
void 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;
353
L1: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
#include"HuffmanTree.h"2
#include<string>3
using namespace std;4

5
//////////////////////////////////////////////////////////////////////////////6
// 构造函数7
// 函数功能:将结点指针初始化为NULL8
// 函数参数:无9
// 参数返回值:无10
HuffmanTree::HuffmanTree()11
{12
Node=NULL; //将树结点初始化为空 13
Info=NULL; //将字符数组初始化为空14
LeafNum=0; //将叶子数初始化为015
}16
//////////////////////////////////////////////////////////////////////////////17
// 析构函数18
// 函数功能:将所有结点的空间释放19
// 函数参数:无20
// 参数返回值:无21
HuffmanTree::~HuffmanTree()22
{23
delete[] Node; //释放结点空间24
delete[] Info; //释放字符存储空间25
}26
//////////////////////////////////////////////////////////////////////////////27
// 初始化函数28
// 函数功能:从终端读入字符集大小n,以及n个字符和n个权值,29
// 建立哈夫曼树,并将它存放在文件hfmTree中.30
// 函数参数:int WeightNum表示代码个数31
// 参数返回值:无 32
void 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
else70
if(Node[j].weight<max2) //比原最小值大但比原次小值要小71
{72
max2=Node[j].weight; //存放次小值73
pos2=j; //修改次小值所在的单元编号74
}75
//for76
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
} //for83
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)); //写入WeightNum96
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
}//Initialization110

111
//////////////////////////////////////////////////////////////////////////////112
// 编码函数113
// 函数功能:利用已建立好的哈夫曼树(如不在内存,则从文件hfmTree中读入),114
// 对文件ToBeTran中的正文进行编码,然后将结果代码存(传输)到文件CodeFile中.115
// 函数参数:无116
// 参数返回值:无117
void 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.txt143
{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) //是左子树,则生成代码0212
code[start++]='0';213
else //是右子树,则生成代码1214
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
} //Encode237

238
//////////////////////////////////////////////////////////////////////////////239
// 译码函数240
// 函数功能:利用已建好的哈夫曼树,对传输到达的CodeFile中的数据代码进行译码,241
// 将译码结果存入文件TextFile中.242
// 函数参数:无243
// 参数返回值:无244
void 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
else285
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
}//while294
fop.close();295
296
cout<<"\n译码成功且已存到文件TextFile.dat中!\n\n";297
}//Decoder298
//////////////////////////////////////////////////////////////////////////////299
// 印文件代码函数300
// 函数功能:将文件CodeFile以紧凑格式显示在终端上,301
// 每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。302
// 函数参数:无303
// 参数返回值:无304
void 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
// 参数返回值:无337
void 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;353
L1:if (Node[m].parent!=-1) //自定义跳转标签354
{355
if (Node[Node[m].parent].lchild==m)356
{357
temp[--k]='1';358
}359
else360
{361
temp[--k]='0';362
}363
m=Node[m].parent;364
goto L1; //跳转到指定的标签L1365
}366
else367
{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
12
int 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
// 程序名:main.cpp2
// 程序功能:主函数源文件3

4
#include"HuffmanTree.h"5
#include<string.h>6
#include<stdlib.h>7

8
//////////////////////////////////////////////////////////////////////////////9
// 主函数10
//参数返回值:无11

12
int 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


