哈夫曼编码译码器实验报告免费文档格式.docx
《哈夫曼编码译码器实验报告免费文档格式.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码译码器实验报告免费文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
的左右子树均为空。
二、选取左右子树
在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树
的根结点的权值为其左右子树的根结点的权值之和。
三、删除左右子树
从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。
四、重复二和三两步,
重复二和三两步,直到集合F中只有一棵二叉树为止。
因此,有如下分析:
1.我们需要一个功能函数对ASCII码的初始化并需要一个数组来保存它们;
2.定义代表森林的数组,在创建哈夫曼树的过程当中保存被选中的字符,即给定报文
中出现的字符,模拟哈夫曼树选取和删除左右子树的过程;
3.自底而上地创建哈夫曼树,保存根的地址和每个叶节点的地址,即字符的地址,然
后自底而上检索,首尾对换调整为哈夫曼树实现哈弗曼编码;
4.从哈弗曼编码文件当中读入字符,根据当前字符为0或者1的状况访问左子树或者
右孩子,实现解码;
5.使用文件读写操作哈夫曼编码和解码结果的写入;
解题方法:
结构体、数组、类的定义:
1.定义结构体类型的signode作为哈夫曼树的节点,定义结构体类型的hufnode作为
哈夫曼编码对照表的节点,定义HFM类实现对哈夫曼树的创建,利用其成员函数
完成哈夫曼编码译码的工作。
2.定义signode类型的全局数组SN[256](为方便调用,之后的forest[256],
hufNode[256]均为全局数组),保存ASCII编码的字符,是否在文章中出现(bool
类型)以及出现次数(int类型,权重),左右孩子节点位置,父节点位置信息;
3.为节省存储空间,定义signode*类型的全局数组forest[256],模拟森林,在创建
哈夫曼树的过程中保存出现字符的指针,模拟哈夫曼树选取和删除左右子树的过
程;
4.定义hufnode类型的全局数组hufNode[256],在编码时最为哈夫曼编码对照表的节
点,char型c保存字符,intcode[100]保存其哈夫曼编码;
5.定义HFM类,主要保存哈夫曼树的根节点指针,但其丰富的功能函数将实现哈夫
曼编码译码的工作及其他功能;
函数介绍:
1.voidinit(signode*sig){……}初始化数组SN[];
2.voidcompress(){……}输出压缩对比情况的信息;
3.voidexchange(){……}用两层for循环实现hufNode[i]节点的成员哈夫曼编码数组
code[]前后元素的对换,因为在之前的编码过程中由于是从叶节点追溯至根节点,
存入code数组的哈夫曼编码与哈夫曼编码的概念反向,故而要调整;
4.signode*getroot(){……}返回哈夫曼树的根节点指针;
5.signode*HFM:
:
creat(){……}创建哈夫曼树,首先用三个for循环查看forest数组,
找到权值最小的两个字符,以int型的min1,min2记录其下标,定义signode*类
型指针pp指向新生成signode节点,用指针操作使pp指向的节点的权值为
min1,min2权值之和,pp做孩子指向forest[min1],右孩子指向forest[min2],
min1,min2的父指针指向pp,然后将pp存入min1的位置,min2之后的每一个节
点依次往前移一个位置,实现从forest数组中清除min1,min2并加入pp的操作;
6.voidHFM:
hufcode(){……}哈夫曼编码,用for循环控制查看hufNode数组,其初
始化已在creat()的开始完成,对每一个字符实现编码,用while循环从叶节点
开始,如果该节点是其父节点的左孩子就将code[hufNode[i].size++]赋值0,否则
赋为1,直至当前节点的父节点为空,while循环结束;
7.voidHFM:
savewithhufcode(FILE*inf,FILE*outf){……}将读入的文章以哈夫曼编
码的形式存储,其中inf为读入文件的指针,outf为写入文件的指针,首先调用
rewind(inf)函数将光标放置在文章开头,防止文件未关闭导致的错误,每读一个字
符就用for循环在hufNode数组中查找,因为hufNode数组就是保存出现的字符
的,故一定可以找到,然后再用fputc函数将code[]数组的内容写入文件,直至读
入文件结束;
8.voidHFM:
inorder(signode*sig){……}迭代法遍历树,遍历到叶节点时执行
hufNode[count++].sig=sig语句实现hufNode数组指向文章中出现的字符;
9.intHFM:
maxc(){……}计数变量,记录哈夫曼编码最大位数;
10.voidHFM:
hufdecode(FILE*ipf,FILE*opf){……}解码,从哈夫曼编码到字符,输出
到屏幕和指定的文件中;
11.voidinput(FILE*f){……}初始读入文章,保存出现的字符记录修改其权重;
数据结构选择与算法设计
数据结构选择:
signode:
structsignode{//signode节点,哈夫曼树节点//
charc;
//字符//
intweight;
//权重//
boolb;
//文章中是否出现//
signode*parent;
signode*left;
signode*right;
signode(){//初始化//
c=NULL;
b=false;
weight=0;
parent=left=right=NULL;
}
};
Cweightbparent
leftright
hufnode:
structhufnode{//哈夫曼编码对照表节点//
signode*sig;
intcode[100];
//保存哈夫曼编码//
intsize;
hufnode(){sig=NULL;
size=0;
b=true;
}};
Sigcode[100]size
HFM:
classHFM{//哈夫曼类//
private:
signode*root;
//哈夫曼树根//
signode*pt;
//编码时做哨兵指针//
intalleaf;
public:
HFM(intall){root=pt=NULL;
alleaf=all;
}//all是森林中树的个数//
~HFM(){}
signode*getroot(){returnroot;
signode*creat();
//创建哈夫曼树//
voidhufcode();
//编码//
voidsavewithhufcode(FILE*inf,FILE*outf);
//用哈弗曼编码存储文件//
voidhufdecode(FILE*ipf,FILE*opf);
//解码//
voidinorder(signode*sig);
intmaxc();
//求取哈弗曼编码最大长度//};
Rootptalleaf
creat()hufcode()savewithhufcode(inf,outf)
inorder(sig)getroot()
hufdecode(ipf,opf)maxc()
算法设计:
初始化SN数组init(SN)
从f1读入字符input(f1)
输出字符信息及权重
huffman.creat()创建哈夫曼树
哈夫曼编码并huffman.hufcode();
用该编码保存exchange();
文件huffman.savewithhufcode(f1,f2);
输入数字选择
compress()1.查看哈2.哈夫曼3.查看压夫曼编码解码缩率
huffman.hufdecode(f2,f3)
测试结果
Doc窗口:
文件读写(部分):
总结
程序分析:
本次哈夫曼编码译码器的课程实验做得还算成功,不仅仅在于程序能够正常运行,实
现应有的功能,关键在于过程,在于小组成员的分工合作和一起纠错排错的过程,在完成程序的过程中才能真正理解面向对象和模块化设计的思想,我们不仅仅是说要每人分几个函数,关键在于这些函数代表的是一个个功能模块,任何一个模块出现问题或者模块之间的衔接出现问题都将导致程序运行的失败。
哈夫曼编码译码器课程实验我主要负责完成编码译码器数据结构和功能模块框架的设计,结构体和类的定义,以及creat函数,hufcode函数,savewithhufcode函数的实现。
在初始设计的时候,我体会到书写流程图的重要性,只有又一个清晰的设计思路才能事半功倍,分工明确,避免无效劳动或者在错误的编程方向上走弯路,也让大家明白自己在程序设计中的位置和职责。
初始的创建是哈夫曼编码译码系统成功的关键,我在创建的过程当中多次使用树的先根,配合中根遍历操作,输出接点字符或者权重信息,作为检验,对验证和纠错起到了非常大的作用。
在适当的地方调用它们,运行时可以看到验证编写程序的正确性;
通过本次实验,提高了自已调试程序的能力。
充分体会到了在程序执行时的提示性输出的重要性。
编写大一点的程序,应先写出算法,再写程序,一段一段调试;
对于没有实现的操作用空操作代替,这样容易找出错误所在。
最忌讳将所有代码写完后再调试,这样若程
。
序有错误,太难找
需要特别强调的是:
1(感觉文件操作自己并不是很熟练,尽管在向显示器输出的时候并没有什么错误但
是读写文件的时候就没那么顺利了,比如说当编写savewithhufcode函数时读文
件,却总不执行,后来通过断点测试发现每次fgetc()返回值总为-1,于是我考虑
是否是文件没有打开或者文件结束的缘故,后来想通了是之前打开的文件光标读
操作结束后仍在结尾故每次总返回-1,故调用rewind函数将光标位置移动到文章
开始。
2.用哈夫曼编码存储文件的时候还应注意数字0,1与字符0,1的不同,不应直接在
fputc()函数中直接