哈夫曼树课程设计报告
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
目: 哈夫曼编码器
院 系:
专业班级:
学 号:
学生姓名:
指导教师:
2014年 1月 2日
课程设计需求分析报告 一、分析问题和确定解决
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
1.分析问题
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统,为这样的信息收发站写一个哈夫曼的编/译码系统。
2.确定解决方案
设计建立带权的哈夫曼树,确定哈夫曼树的类与成员函数,以及各函数之间的调用关系,采用动态数组的存储结构存储所需要的数据,通过不同的函数来实现编码,译码以及打印二进制编码、哈夫曼树,把不同的数据存入不同的txt文件中,通过主函数调用来实现功能
检测
工程第三方检测合同工程防雷检测合同植筋拉拔检测方案传感器技术课后答案检测机构通用要求培训
。
3.输入的形式和输入值的范围
手动或者从文本中读入数据的形式初始化哈夫曼树,从键盘中或者文件中读入数据,以字母A-Z代表结点,以自然数代表权值,字符串提示使用者所要执行的操作。 4.输出的形式
在显示器界面上或者以文本的形式来实现程序调试的输出。
5.程序所能达到的功能
(1)初始化。手动输入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件WritehfmTree中,输出哈夫曼树及各字符对应的编码存于WritehfmCode;从文本中读入字符,建立哈夫曼树存于ReadhfmTree, 输出哈夫曼树及各字符对应的编码存于ReadhfmCode.
(2)编码。手动输入一串大写英文字符,该字符存于WriteToBeTron中,对字符进行编码并将它存于WriteCodeFile中;从文件中读取字符编码并存于ReadCodeFile中。 (3)印代码文件。将文件ReadCodeFile以紧凑格式显示在终端上,每行50个代码。同时将
此字符形式的代码码写入文件CodePrint中。
(4)印哈夫曼树。将初始化的哈夫曼树以直观的方式显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
各个功能数据输出存储位置(如表1所示)
表1:各个功能数据输出存储位置表
功能 字母 二进制码
WritehfmTree(手动) WritehfmCode(手动) 初始化 ReadhfmTree(文本读入) ReadhfmCode(文本读入)
hfmTree(默认文本读入) hfmCode(默认文本读入)
WriteToBeTron(手动) WriteCodeFile(手动) 编码 ReadCodeFile(文本读入)
CodePrint 印编码代码
TreePrint 印哈夫曼树
6.测试数据
(1)正确的输入:1>输入主菜单项中的英文字母I(i),E(e),D(d),P(p),Q(q)
输出结果:进入所选的功能界面
2>输入子菜单项中的数字1,2,3,(4)
输出结果:执行所选的功能
(2)含有错误的输入:1>输入除了主菜单项中的英文字母I(i),E(e),D(d),P(p),Q(q)
输出结果:<您的输入有误,请重新输入:>
2>输入除了子菜单项中的数字1,2,3,(4)
输出结果:<您的输入有误,请重新输入:>
7.程序说明
(1)程序中数据类型的定义:用到三组结构体,分别是哈夫曼树的动态数组存储结构*HuffmanTree,哈夫曼编码表的存储结构HuffmanCode,字符结点的动态数组存储结构wElem以及哈夫曼树类定义class Huffman。
(2)主程序的流程图:
用户从主菜单中选择所要进行的操作,如果输入选项错误则提示重新输入选项,否则进入选中的操作项(如图1所示)。
图1:主程序流程图
(3)各程序模块之间的层次(调用)关系:
主函数main()调用初始化,编码,译码,打印二进制编码,打印哈夫曼树这五个子函数;进入初始化功能后调用手动输入,文本读入,默认文本这三个函数;进入编码功能后调用手动编码,文本读入编码这两个函数;进入译码功能后调用手动译码,文本读入译码这两个函数(如图2所示)。
图2::各程序模块之间的层次(调用)关系
(4)默认的哈夫曼树:
空格以及字母A—Z频度分别为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建立一棵默认的哈夫曼树(如图3
所示)。
图3:默认的哈夫曼树 二、详细设计
1、哈夫曼树存储及类的定义:
#include
#include
#include
#include
#include
typedef struct //哈夫曼树的存储结构 {
int weight; //权值
char HTch; //字符
int parent,lchild,rchild; //双亲,左孩子,右孩子 }HTNode,*HuffmanTree; //动态数组存储哈夫曼树 typedef struct //哈夫曼编码表的存储结构 {
char ch; //字符
char* hufCh; //二进制码
}HuffmanCode; //动态数组存储哈夫曼编码表
typedef struct //字符结点
{
char ch; //字符
int wt; //字符权值
}wElem; //动态分配数组存储读入字符与权值
class Huffman
{
public:
Huffman(){}; //构造函数
~Huffman(){}; //析构函数
void Initialization(HuffmanTree &HT,HuffmanCode *HC,int &n);//初始化,手动
void Initialization(HuffmanTree &HT,HuffmanCode *HC,int &n,int v);
//初始化,
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
文件
void Initialization(HuffmanTree &HT,HuffmanCode *HC,char*InitFile,int &n);
//初始化,统计
void EnCoding(HuffmanCode *HC,int hufnum); //手动编码
void EnCoding(HuffmanCode *HC,char*EnCodeFile); //文件读入编码
void Print(char *);//打印二进制编码
void Treeprinting( HTNode T,HuffmanTree HT,int n );//打印哈夫曼树 };
2、哈夫曼树的基本操作:
//手动输入字符与权值并初始化
void Huffman::Initialization(HuffmanTree &HT,HuffmanCode *HC,int &n)//哈夫曼树对象,编
码对象,字符数 //从文件读入标准哈夫曼树并初始化
void Huffman::Initialization(HuffmanTree &HT,HuffmanCode *HC,int &n,int v)//哈夫曼树对
象,编码对象,字符
数,区分功能参数 //从文件中统计字符与权值,构造哈弗曼树
void Huffman::Initialization(HuffmanTree &HT,HuffmanCode *HC,char*InitFile,int &n)//哈夫
曼树对象,编码对
象,文件名,字符数 //编码函数,对用户输入的文件的正文进行编码,然后将结果存入文件WriteCodeFile.txt中 void Huffman::EnCoding(HuffmanCode *HC,int hufnum)//编码数组对象,字符数 //编码函数,从文件读取
void Huffman::EnCoding(HuffmanCode *HC,char*EnCodeFile)//编码数组对象,文件名 //译码函数,对文件CodeFile中的代码进行译码,结果存入文件ReadTextFile.txt中 void Huffman::DeCoding(HuffmanTree HT,HuffmanCode *HC,char*DeCodeFile,int n)//哈夫曼
树对象,编码对象,
文件名,字符数 //译码函数,手动输入
void Huffman::DeCoding(HuffmanTree HT,HuffmanCode *HC,int n)//哈夫曼树对象,编码对
象,字符数
//打印函数,将文件CodePrint.txt中的内容以每行个代码显示在屏幕上 void Huffman::Print(char* cfileName) //文件名
//打印哈夫曼树
void coprint(HuffmanTree start,HuffmanTree HT) //哈夫曼树对象,哈夫曼树对象 其中部分操作的伪代码如下:
(1)从文件读入标准哈夫曼树并初始化
void Huffman::Initialization(HuffmanTree &HT,HuffmanCode *HC,int &n,int v)//哈夫曼树对象,编码对象,字符数,区分功能参数
{定义一个动态数组存放空格和26个英文字母,把字符串" ABCDEFGHIJKLMNOPQRSTUVWXYZ"
读入文件"CharFile.txt"
while(charRead.get(inbuf))
{
w[j].ch=inbuf;
w[j].wt=cw[j];
j++;
}
//w存放n字符及其权值(从0号单元开始),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC.
int i,m,ww=0; //n:字符数 m:树结点数
int s1,s2;
HuffmanTree p; //定义指针变量p
if(n<=1) return; //小于2个字符,结束
m=2*n-1; //n个叶子,2*n-1个结点
HT=new HTNode[(m+1)*sizeof(HTNode)];
HT[0].parent=-1;HT[0].lchild=-1;HT[0].rchild=-1;HT[0].weight=0;
for(p=HT+1,i=1;i<=n;i++,p++,ww++)//初始化n个叶子结点(即n个字符)
{
p->weight=w[ww].wt;
p->HTch=w[ww].ch;
p->parent=p->lchild=p->rchild=0;
}//跳出循环时i=n+1;
for(;i<=m;i++,++p)//初始化叶子结点之外的其它所有结点
{
p->weight=0;
p->HTch='#';
p->parent=p->lchild=p->rchild=0;
}
for(i=n+1;i<=m;i++)//建立哈夫曼树
{
Select(HT,i-1,s1,s2);//在HT数组的至i-1个结点中选择parent为且权值weight
最小的两个结点,其序号分别为S1和S2;
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
char *cd=new char[n];//分配编码的存储空间
cd[n-1]='\0';//编码结束符
int c,f,start;
for(i=1;i<=n;i++)//逐个字符求哈夫曼编码
{
start=n-1;
for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)
{
if(HT[f].lchild==c)
cd[--start]='0';
else
cd[--start]='1';
}
HC[i].ch=w[i-1].ch;//复制字符
HC[i].hufCh=new char [(n-start)*sizeof(char)];//为第i个字符编码分配空间
strcpy(HC[i].hufCh,&cd[start]);//从cd复制编码(串)到HC
}
//向屏幕输出哈夫曼编码,并把编码保存在文件hfmCode.txt中; ,
(2)编码函数,从文件读取
void Huffman::EnCoding(HuffmanCode *HC,char*EnCodeFile)//编码数组对象,文件名
{对文件进行编码,并将编码存于文件ReadCodeFile.txt中 while(ufileRead.get(charInbuf)) {
for(int k=1;k<=27;k++)
{
if(charInbuf==HC[k].ch)
{
codeWrite<:";
int k=1; Huffman hf; //类对象
while(k)
{//将小写转化为大写}
switch(c)
{ case'I': //进入初始化选择界面
{
//选择初始化方式后,进入子菜单
switch(c){
case ‘1’:{hf.Initialization(HT,HC,current_n);break; }//手动初始化
case ‘2’:{//输入需要初始化的文件名(需包含后缀名.txt)建立哈夫曼树;
//建立哈夫曼树,并把哈夫曼树存放在ReadhfmTree.txt中
hf.Initialization(HT,HC,buf,current_n); break;
//从文件读入数据初始化
}
case ‘3’: {hf.Initialization(HT,HC,current_n,0); //标准初始化 }
case ‘4’: break;
}
break;
}
case'E': //进入编码选择界面
{//选择字符序列读入方式后进入子菜单
switch(c){
case '1':{hf.EnCoding(HC,hufnum); break; //手动编码 }
case '2':{ //输入需要的文件名(需包含后缀名.txt) 进行编码
hf.EnCoding(HC,buf); break; //文件读入编码
}
case '3': break;
}
break;
}
case'P': //进入打印二进制编码界面
{ hf.Print("ReadCodeFile.txt"); break;}
case'T': //进入打印哈夫曼树界面
{ hf.Treeprinting(HT[2*current_n-1],HT,current_n);break;}
case'Q':exit(-1); //退出
default:exit(-1);
}
}
}
三、系统调试与测试
1、调试过程中遇到的问题及解决办法:
(1)逐个手动输入字符和权值进行编码,若数据太大效率太低。
解决办法:后来增加一个新的功能从文本中读入数据,这样可大大提高效率。 (2)初始化文本读入时,若数据过大,会结束进程,无法进行操作。
解决办法:增加动态数组的最大上限,当超过上限,会提示“文本数据过大”,而且可以显示范围内的数据。
(3)只能读取固定的文件进行编码。
解决办法:可以手动输入想要读取的文件名。
(4)只能打印默认的哈夫曼树
解决办法:通过增加两种初始化方式(手动初始化和文本读入初始化),打印用户当前初始化的哈夫曼树。
(5)进入子菜单后,输入的选项必须为数字,否则会出现死循环。
解决办法:把输入的数据类型由整型改为字符型。
2、测试数据及其输出结果:
(1)进入主菜单界面,用户可以选择所要执行的操作,比如:初始化<建立哈夫曼树>,编码,译码,打印二进制编码代码,打印哈夫曼树。在执行编码、译码操作前,请先初始化默认的哈夫曼树(如图4所示) 。
图4:主菜单界面
(2)进入初始化界面,用户可以选择执行手动初始化(如图5所示),初始化结果存入WritehfmCode.txt,WritehfmTree.txt ;文本读入初始化(如图6所示),初始化结果存入ReadhfmCode.txt,ReadhfmTree.txt;默认文本初始化(如图7所示),初始化结果存入hfmCode.txt,hfmTree.txt。
图5:手动初始化哈夫曼树
图6:文本读入初始化哈夫曼树
图7:默认文本初始化
(3)进入编码界面,用户可以选择执行手动编码(如图8所示),编码结果存入WriteCodeFile.txt;文本读入编码(如图9所示),编码结果存入ReadCodeFile.txt。
图8:手动编码
图9:文本读入编码
(5)进入打印编码代码界面(如图12所示),打印结果存入CodePrint.txt。
图12:打印编码代码
(6)进入打印哈夫曼树,打印结果存入TreePrint.txt。打印默认哈夫曼树(如图13所示),打印频度差距大的哈夫曼树(如图14所示),打印频度差距小的哈夫曼树(如图15所示)
图13:打印默认哈夫曼树
图14:打印频度差距大的哈夫曼树
图15:打印频度差距小的哈夫曼树
四、结果分析
1、算法的时空分析和改进设想(选取主要函数)
(1)程序算法分析:
经过对程序中哈夫曼树的基本操作函数及其他相关算法的时空间复杂度的分析可知本
程序中哈夫曼树的基本操作函数及相关算法的空间复杂度良好,但哈夫曼树的Initialization以及DeCoding操作函数的时间复杂度比较复杂,不过从总体的算法效率看,哈夫曼树的
基本操作函数及其他相关算法时间及空间复杂度良好,总体效率良好。 (2)主要函数时空分析(n代表字符种类数)(如表2所示):
表2:主要函数时空分析表
基本操作 时间复杂度分析 空间复杂度分析
Initialization O(n*n) S(n)
EnCoding O(n) S(n)
O(n) S(n)
DeCoding O(n*n) S(n)
O(n*n) S(n)
Print O(n) S(n)
Treeprinting O(n) S(n)
(3)改进设想:
1当前使用的是一维动态数组存储,当哈夫曼函数添加增加、删除、修改这些功能时,可选用链式存储哈夫曼树,效率会更高。
2、当前程序只能识别大写英文字母和空格,可改进为输入小写字母时也可识别。
3、当前程序是在先序遍历哈夫曼树时,采用递归算法,可以设计一个非递归算法遍历哈夫曼树,这样可以降低时间复杂度,提高程序运行速率。
2、经验和体会
一周的课程设计结束了,在这次的课程设计中不仅检验了我们所学习的知识,也培养了我们如何去把握一件事情,如何去做一件事情,又如何完成一件事情。在设计过程中,与组员分工设计,相互探讨,相互学习,相互监督,学会了合作,学会了运筹帷幄,学会了宽容,学会了理解,也学会了做人与处世。
完成这次的课程设计任务,我们要做好以下准备:
(1)首先要熟练掌握二叉树的性质、先序遍历二叉树、最优二叉树的构建、字符串匹配等,然后在此基础上掌握理解huffman树和编码和译码。
(2) 完成哈夫曼编译器,我们要考虑如何把文件当中的英文字母编成二进制代码,如何将二进制代码翻译成英文字母以及如何构建一棵哈夫曼树。
在这次的课程设计任务中,我们遇到的问题和困难:
(1)起初功能太简单,经过讨论,我们增加了一些必要的选择功能,比如:读入方式分为文本读入和手动读入。
(2)逐个手动输入字符和权值进行编码,若数据太大效率太低。后来增加一个新的功能从文本中读入数据,这样可大大提高效率。
(3)初始化文本读入时,若数据过大,会结束进程,无法进行操作。后来增加动态数组的最大上限,当超过上限,会提示“文本数据过大”,而且可以显示范围内的数据。
每次出现问题我们都一起讨论,研究解决和改进的
方法
快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载
。这次课程设计的成功,可以说是我们五个人一起努力的成果。我们小组由五个人组成,每个人都有自己在小组中的作用,黄志发:编写代码,设计界面 ,调试程序 / 施鸿俊、赖玉丹:测试数据 / 邱琳娜、胡明丽:文档编写和整理。
我们总是在不断地调试程序和改进程序的功能,皇天不负有心人,我们终于在自己的努力和老师的辛勤指导下顺利完成了课程设计。
五、参考文献
1 《数据结构》(c++语言描述),殷人昆主编,清华大学出版社
2《数据结构题集》,严蔚敏编著,清华大学出版社
六、附录
1、源程序文件:
Huffman.h:包含哈夫曼树结构体、哈夫曼编码结构体、结点结构体,哈夫曼树的类定义 Huffman.cpp:哈夫曼树类的成员函数实现
main.cpp:程序的入口,包含主界面和各个功能函数的调用
2、输入数据文本:
News.txt:存储了一篇较大规模的大写英文文章,用于文件读入编码和文件读入初始化 123.txt:存储了较小规模的大写英文文章,用于文件读入编码和文件读入初始化 321.txt:存储了较小规模的0,1代码,用于文件读入进行译码
3、小组成员及分工表(如表3所示):