哈夫曼树的应用Word格式文档下载.docx
《哈夫曼树的应用Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《哈夫曼树的应用Word格式文档下载.docx(26页珍藏版)》请在冰豆网上搜索。
![哈夫曼树的应用Word格式文档下载.docx](https://file1.bdocx.com/fileroot1/2022-11/20/bfea8f58-e24d-47c0-b70b-f2e6abdd4b9e/bfea8f58-e24d-47c0-b70b-f2e6abdd4b9e1.gif)
2、本演示程序中,用户可以输入键盘中的任意字符,长度为任意长,字符输入顺序不限,且允许出现重码
3、演示程序以用户与计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令,相应的输入数据(可虑去输入中的非法字符)和运算结果显示在其后。
4、本演示程序中,当用户选择的功能错误时,系统会输出相应的提示。
5、在本系统中,用户可以对任意长的字符串可进行编码/译码。
6、程序执行的命令包括:
1)初始化(I) 2)编码(E) 3)译码(D)
4)印代码文件(P) 5)印哈夫曼树(T) 6)退出(Q)
7、测试数据:
(二)、概要设计
为实现上述程序功能,应以指针存储结点。
为此,需要定义一个抽象数据类型。
1.抽象数据类型定义为:
ADTHuffmanTree{
数据对象:
D={ai|ai∈CharSet,i=1,2,……,n,n≥0}
数据关系:
R={<
ai-1,ai>
ai-1,ai∈D,ai-1基本操作P:
HuffmanTree();
构造函数
~HuffmanTree();
析构函数
Initialization(intWeightNum);
操作结果:
构造哈夫曼树。
Encoder()
初始条件:
哈夫曼树已存在或者哈夫曼树已存到文件中。
对字符串进行编码
Decoder();
哈夫曼树已存在且已编码。
对二进制串进行译码
Print()
编码文件已存在。
把已保存好的编码文件显示在屏幕
TreePrinting()
哈夫曼树已存在。
将已在内存中的哈夫曼树以直观的方式显示在终端上
2.本程序包含三个模块:
1)主程序模块:
voidmain(){
初始化;
do{
接受命令;
处理命令;
}while(“命令”=”退出”)
}
2)、建树模块——实现定义的抽象数据类型
3)、编/译码模块——实现字符串的编/译码
各模块之间的调用关系如下:
主程序模块
建树模块
编/译码模块
程序代码如下
//程序名:
HuffmanTree.h
//程序功能:
哈夫曼树类的头文件(并用其来实现编/译码)
//作者:
蔡丽敏
//日期:
2008.12.27
//版本:
1.0
//对应类实现文件:
HuffmanTree.cpp
//对应主程序文件:
main.cpp
1//程序名:
HuffmanTree.h
2//程序功能:
哈夫曼树类的头文件(并用其来实现编/译码)
3
4//对应类实现文件:
HuffmanTree.cpp
5//对应主程序文件:
main.cpp
6
7
8
9#include<
iostream>
10#include<
fstream>
11#include<
string>
12usingnamespacestd;
13structHuffmanNode//定义哈夫曼树各结点
14{
15intweight;
//存放结点的权值,假设只考虑处理权值为整数的情况
16intparent;
//记录结点父亲位置,-1表示为根结点,否则表示为非根结点
17intlchild,rchild;
//分别存放该结点的左、右孩子的所在单元的编号
18};
19classHuffmanTree//建立哈夫曼树类
20{
21private:
22HuffmanNode*Node;
//哈夫曼树中结点的存储结构
23char*Info;
//用来保存各字符信息
24intLeafNum;
//树中的叶子结点总数
25public:
26HuffmanTree();
//构造函数
27~HuffmanTree();
//析构函数
28voidInitialization(intWeightNum);
//初始化函数:
根据WeightNum个权值建立一棵哈夫曼树
29voidEncoder();
//编码函数:
利用构造好的哈夫曼树对字符进行编码
30voidDecoder();
//译码函数:
对二进制串进行译码
31voidPrint();
//印文件函数:
把已保存好的编码文件显示在屏幕
32voidTreePrinting();
//印哈夫曼树函数:
将已在内存中的哈夫曼树以直观的方式显示在终端上
33};
HuffmanTree.cpp
实现哈夫曼树类的源文件(并用其来实现编/译码)
蔡丽敏
1#include"
HuffmanTree.h"
2#include<
3usingnamespacestd;
45/**///////////////////////////////////////////////////////////////////////////////
6//构造函数
7//函数功能:
将结点指针初始化为NULL
8//函数参数:
无
9//参数返回值:
10HuffmanTree:
:
HuffmanTree()
11{
12Node=NULL;
//将树结点初始化为空
13Info=NULL;
//将字符数组初始化为空
14LeafNum=0;
//将叶子数初始化为0
15}
16/**///////////////////////////////////////////////////////////////////////////////
17//析构函数
18//函数功能:
将所有结点的空间释放
19//函数参数:
20//参数返回值:
21HuffmanTree:
~HuffmanTree()
22{
23delete[]Node;
//释放结点空间
24delete[]Info;
//释放字符存储空间
25}
26/**///////////////////////////////////////////////////////////////////////////////
27//初始化函数
28//函数功能:
从终端读入字符集大小n,以及n个字符和n个权值,
29//建立哈夫曼树,并将它存放在文件hfmTree中.
30//函数参数:
intWeightNum表示代码个数
31//参数返回值:
无
32voidHuffmanTree:
Initialization(intWeightNum)//初始化
33{
34inti,j,pos1,pos2,max1,max2;
//
35
36Node=newHuffmanNode[2*WeightNum-1];
//WeightNum权值对应的哈夫曼树中的结点总数为2*WeightNum-1个
37//Info=newchar[2*WeightNum-1];
38Info=newchar[WeightNum];
39for(i=0;
i<
WeightNum;
i++)
40{
41cout<
<
"
请输入第"
i+1<
个字符值"
;
42getchar();
//丢弃字符'
\t'
与'
\n'
43Info[i]=getchar();
//输入一个字符,主要是考虑输入空格而采用这种形式的
44//cin>
>
Info[i];
45getchar();
46cout<
请输入该字符的权值或频度"
47cin>
Node[i].weight;
//输入权值
48Node[i].parent=-1;
//为根结点
49Node[i].lchild=-1;
//无左孩子
50Node[i].rchild=-1;
//无右孩子
51}
52
53for(i=WeightNum;
2*WeightNum-1;
i++)//表示需做WeightNum-1次合并
54{
55pos1=-1;
56pos2=-1;
//分别用来存放当前最小值和次小值的所在单元编号
57max1=32767;
//32767为整型数的最大值
58max2=32767;
//分别用来存放当前找到的最小值和次小值
59
60for(j=0;
j<
i;
j++)//在跟节点中选出权值最小的两个
61if(Node[j].parent==-1)//是否为根结点
62if(Node[j].weight<
max1)//是否比最小值要小
63{
64max2=max1;
//原最小值变为次小值
65max1=Node[j].weight;
//存放最小值
66pos2=pos1;
//修改次小值所在单元编号
67pos1=j;
//修改最小值所在单元编号
68}
69else
70if(Node[j].weight<
max2)//比原最小值大但比原次小值要小
71{
72max2=Node[j].weight;
//存放次小值
73pos2=j;
//修改次小值所在的单元编号
74}
75//for
76Node[pos1].parent=i;
//修改父亲位置
77Node[pos2].parent=i;
78Node[i].lchild=pos1;
//修改儿子位置
79Node[i].rchild=pos2;
80Node[i].parent=-1;
//表示新结点应该是根结点
81Node[i].weight=Node[pos1].weight+Node[pos2].weight;
82}//for
83LeafNum=WeightNum;
84
85
86charch;
87cout<
是否要替换原来文件(Y/N):
88cin>
ch;
89if(ch=='
y'
||ch=='
Y'
)
90{
91ofstreamfop;
//以二进制方式打开hfmTree.dat文件,并当重新运行时覆盖原文件
92fop.open("
hfmTree.dat"
ios:
out|ios:
binary|ios:
trunc);
93if(fop.fail())//文件打开失败
94cout<
文件打开失败!
\n"
95fop.write((char*)&
WeightNum,sizeof(WeightNum));
//写入WeightNum
96for(i=0;
i++)//把各字符信息写入文件
97{
98fop.write((char*)&
Info[i],sizeof(Info[i]));
99flush(cout);
100}
101for(i=0;
i++)//把个节点内容写入文件
102{
103fop.write((char*)&
Node[i],sizeof(Node[i]));
104flush(cout);
105}
106fop.close();
//关闭文件
107}
108cout<
哈夫曼树已构造完成。
109}//Initialization
110
111/**///////////////////////////////////////////////////////////////////////////////
112//编码函数
113//函数功能:
利用已建立好的哈夫曼树(如不在内存,则从文件hfmTree中读入),
114//对文件ToBeTran中的正文进行编码,然后将结果代码存(传输)到文件CodeFile中.
115//函数参数:
116//参数返回值:
117voidHuffmanTree:
Encoder()
118{
119if(Node==NULL)//哈夫曼树不在内存,从文件hfmTree中读入
120{
121ifstreamfip;
//以二进制方式打开hfmTree.dat文件
122fip.open("
in);
123if(fip.fail())//文件打开失败
124{
125cout<
126return;
//结束本函数
127}
128fip.read((char*)&
LeafNum,sizeof(LeafNum));
//读取叶子数
129Info=newchar[LeafNum];
130Node=newHuffmanNode[2*LeafNum-1];
131for(inti=0;
LeafNum;
i++)//读取字符信息
132fip.read((char*)&
133for(i=0;
2*LeafNum-1;
i++)//读取结点信息
134fip.read((char*)&
135}
136
137char*Tree;
//用于存储需编码内容
138inti=0,num;
139charChoose;
//让用户选择读取文件或重新输入需编码内容
140cout<
你要从文件中读取内容
(1),还是重新输入
(2):
141cin>
Choose;
142if(Choose=='
1'
)//读取文件ToBeTran.txt
143{
144ifstreamfip1("
ToBeTran.txt"
);
145if(fip1.fail())//文件不存在
146{
147cout<
文件打开失败!
148return;
149}
150charch;
151intk=0;
152while(fip1.get(ch))
153{
154k++;
//计算CodeFile中代码长度
155}
156fip1.close();
157
158Tree=newchar[k+1];
159ifstreamfip2("
160
161k=0;
162while(fip2.get(ch))
163{
164Tree[k]=ch;
//读取文件内容,并存到Tree中
165k++;
166}
167fip2.close();
168Tree[k]='
\0'
//结束标志
169cout<
需编码内容为:
170cout<
Tree<
endl;
171}//if(Choose=='
172
173else//Choose!
='
重新输入
174{
175stringtree;
//用于输入需编码内容,由于string类对象可以输入任意长度,
176//所以先利用这个对象输入,再转存在Tree中
177
178cin.ignore();
179cout<
请输入需要编码的内容(可输入任意长,结束时请按2下回车):
180getline(cin,tree,'
//输入任意长字符串,
181//getline以回车('
)作为结束符,第一次按回车表示字符串结束,第二次按回车才开始输出。
182while(tree[i]!
183i++;
184num=i;
//计算tree长度
185i=0;
186Tree=newchar[num+1];
187while(tree[i]!
)//将tree中的字符转存到Tree中
188{
189Tree[i]=tree[i];
190i++;
191}
192Tree[i]='
//结束标志符
193}
194
195ofstreamfop("
CodeFile.dat"
//存储编码后的代码,并覆盖原文件
196i=0;
197intk=0;
198char*code;
199code=newchar[LeafNum];
//为所产生编码分配容量为LeafNum的存储空间
200//因为不等长编码中最长的编码一定不会超过要求编码的字符个数
201while(Tree[k]!
)//对每一个字符编码
202{
203intj,start=0;
204for(i=0;
205if(Info[i]==Tree[k])//求出该文字所在单元的编号
206break;
207j=i;
208while(Node[j].parent!
=-1)//结点j非树根
209{
210j=Node[j].parent;
//非结点j的双亲结点
211if(Node[j].lchild==i)//是左子树,则生成代码0
212code[start++]='
0'
213else//是右子树,则生成代码1
214code[start++]='
\
215i=j;
216}
217code[start]='
//置串结束符
218
219
220for(i=0;
start/2;
i++)//对二进制序列进行逆置
221{
222j=code[i];
223code[i]=code[start-i-1];
224code[start-i-1]=j;
225}
226i=0;
227while(code[i]!
)//存储代码
228{
229fop<
code[i];
230i++;
231}
232k++;
233}
234fop.close();
235cout<
已编码!
且存到文件CodeFile.dat中!
\n\n"
236}//Encode
237
238/**///////////////////////////////////////////////////////////////////////////////
239//译码函数
240//函数功能:
利用已建好的哈夫曼树,对传输到达的CodeFile中的数据代码进行译码,
241//将译码结果存入文件Te