1. 实验目的与要求
在学习和理解二叉树的原理、构造及遍历方法的基础上,应用所学知识来解决实际问题。
本实验将通过一个实际应用问题的解决过程掌握Huffman树的构造、Huffman编码的生成及基于所获得的Huffman编码压缩文本文件。
涉及的知识点包括树的构造、遍历及C语言位运算和二进制文件。
2. 实验内容
Huffman编码文件压缩
【问题描述】
编写一程序采用Huffman编码对一个正文文件进行压缩。具体压缩方法如下:
1. 对正文文件中字符(换行字符'\n'除外,不统计)按出现次数(即频率)进行统计。
2. 依据字符频率生成相应的Huffman树(未出现的字符不生成)。
3. 依据Huffman树生成相应字符的Huffman编码。
4. 依据字符Huffman编码压缩文件(即将源文件字符按照其Huffman编码输出)。
说明:
1. 只对文件中出现的字符生成Huffman树,注意:一定不要处理\n,即不要为其生成Huffman编码。
2. 采用ASCII码值为0的字符作为压缩文件的结束符(即可将其出现次数设为1来参与编码)。
3. 在生成Huffman树前,初始在对字符频率权重进行(由小至大)排序时,频率相同的字符ASCII编码值小的在前;新生成的权重节点插入到有序权重序列中时,若出现相同权重,则将新生成的权重节点插入到原有相同权重节点之后(采用稳定排序)。
4. 在生成Huffman树时,权重节点在前的作为左孩子节点,权重节点在后的作为右孩子节点。
5. 遍历Huffman树生成字符Huffman码时,左边为0右边为1。
6. 源文件是文本文件,字符采用ASCII编码,每个字符占8个二进制位;而采用Huffman编码后,高频字符编码长度较短(小于8位),因此最后输出时需要使用C语言中的位运算将字符的Huffman码依次输出到每个字节中。
【输入形式】
对当前目录下文件input.txt进行压缩。
【输出形式】
将压缩后结果输出到文件output.txt中,同时将压缩结果用十六进制形式(printf("%x",...))输出到屏幕上,以便检查和查看结果。
3. 实验准备
1.文件下载
从教学平台(judge.buaa.edu.cn)课程下载区下载文件lab_tree2.rar,该文件中包括了本实验中用到的文件huffman2student.c和input.txt:
l huffman2student.c:该文件给出本实验程序的框架,框架中部分内容未完成(见下面相关实验步骤),通过本实验补充完成缺失的代码,使得程序运行后得到相应要求的运行结果;
l input.txt:为本实验的测试数据。
2. huffman2student.c文件中相关数据结构说明
结构类型说明:
struct tnode { //Huffman树结构节点类型
char c;
int weight;
struct tnode *left;
struct tnode *right;
} ;
结构类型struct tnode用来定义Huffman树的节点,其中;
1)对于树的叶节点,成员c和weight用来存放字符及其出现次数;对于非叶节点来说,c值可不用考虑,weight的值满足Huffman树非叶节点生成条件,若p为当前Huffman树节点指针,则有:
p->weight = p->left->weight + p->right->weigth;
2)成员left和right分别为Huffman树节点左右子树节点指针。
全局变量说明:
int Ccount[128]={0};
struct tnode *Root=NULL;
char HCode[128][MAXSIZE]={0};
int Step=0;
FILE *Src, *Obj;
整型数组Ccount存放每个字符的出现次数,如Ccount[‘a’]表示字符a的出现次数。
变量Root为所生成的Huffman树的根节点指针。
数组HCode用于存储字符的Huffman编码,如HCode['a']为字符a的Huffman编码,本实验中为字符串”1000”。
变量Step为实验步骤状态变量,其取值为1、2、3、4,分别对应实验步骤1、2、3、4。
变量Src、Obj为输入输出的文件指针,分别用于打开输入文件“input.txt”和输出文件“output.txt”。
4. 实验步骤
【步骤1】
1) 实验要求
在程序文件huffman2student.c中“//【实验步骤1】开始”和“ //【实验步骤1】结束”间编写相应代码,以实现函数statCount,统计文本文件input.txt中字符出现频率。
//【实验步骤1】开始
void statCount()
{
}
//【实验步骤1】结束
2) 实验说明
函数statCount用来统计输入文件(文件指针为全局变量Src)中字符的出现次数(频率),并将字符出现次数存入全局变量数组Ccount中,如Ccount[‘a’]存放字符a的出现次数。
注意:在该函数中Ccount[0]一定要置为1,即Ccount[0]=1。编码值为0(’\0’)的字符用来作为压缩文件的结束符。
3) 实验结果
函数print1()用来打印输出步骤1的结果,即输出数组Ccount中字符出现次数多于0的字符及次数,编码值为0的字符用NUL表示。完成【步骤1】编码后,本地编译并运行该程序,并在标准输入中输入1,程序运行正确时在屏幕上将输出如下结果:
图1步骤1运行结果
在本地运行正确的情况下,将你所编写的程序文件中//【实验步骤1】开始”和“ //【实验步骤1】结束”间的代码拷贝粘贴到实验报告后所附代码【实验步骤1】下的框中,然后点击提交按钮,若得到如下运行结果(测试数据1评判结果为完全正确):
表明实验步骤1:通过,否则:不通过。