【实习题目】
文本文件的哈夫曼编码压缩实现
【问题描述】
哈夫曼编码是一种有效且可逆的编码方式。要求用哈夫曼编码方式实现对一个文本文件的压缩操作。
【基本要求】
1)
要求程序同时具有哈夫曼编码压缩和解压的功能模块。
2)
压缩模块:统计源文件中各字符出现频率,建立哈夫曼树,通过哈夫曼树求得各字符的哈夫曼编码,最后将哈夫曼树的数据和编码数据写入压缩文件。
3)
解压模块:从压缩文件中读取哈夫曼数据和编码后的数据,解码得到源文件。
【需求分析】
1)
考虑制作图形化界面。
2)
保证有压缩效果。即,生成的压缩文件应该比源文件体积小。
3)
解压缩后的文件应该与源文件完全一致。
4)
最好保留程序调试功能以便于检查错误。
【概要设计】
(本实验程序使用Delphi 2005编写)
设计程序界面如下:
“选择文件”按钮:选择磁盘上的文件,用于压缩或解压;
“压缩”按钮:对选定文件执行压缩操作;
- 包括统计文件中字符出现频率、建立哈夫曼树、获取字符编码以及写入文件四个执行步骤。
“解压”按钮:对选定文件执行解压操作;
- 包括检查压缩文件合法性、从文件读取哈夫曼编码、写入解码文件三个步骤。
“调试模式”复选框:让程序以调试模式运行;
- 正常模式下,执行完压缩或解压操作后程序将自动退出;调试模式下不立即退出,可执行检查哈夫曼树、查看编码等操作。
“退出”按钮:结束程序。
主要数据结构为二叉链表表示的哈夫曼二叉树,辅助数据结构有用于求字符频率的线性表等。
(1)
数据类型定义
type
HuffmanTree = ^HTNode;
HTNode = record
data: Integer;
dataC: Char;
lchild, rchild: HuffmanTree;
end;
// 二叉树。为了方便,字符型和整数型的数据域各设置了一个。
HuffmanElem = record
ch: Char;
freq: Integer;
code: string;
end;
HuffmanTableArr = Array of HuffmanElem;
HuffmanTable = record
data: HuffmanTableArr;
top: SmallInt;
end;
// 线性表。top域用于表中元素个数,即叶节点个数。
// 对每个元素而言,ch存放字符本身,freq存放字符在源文件中出现的频数,code存放其编码。
// 程序刚开始时此表为空。执行求频数操作后得ch和freq域的值,编码结束后才能得code域的值。
TZipForm = class(TForm)
...
end;
// TZipForm窗体类。为本程序运行的主窗体。具体定义略。
(2)
压缩模块
procedure enc_GetHuffmanFreq(F: TStrings; var H: HuffmanTable);
// 求字符串表F中各字符的出现频数,录入线性表H各元素的freq域中。
// 其中F从读入的文本文件中直接载入。
procedure enc_HuffmanCoding(var H: HuffmanTable; var T: HuffmanTree);
// 根据线性表H中已经求得的各字符出现频率,自下而上构建哈夫曼树T。
// 哈夫曼树的具体构造方法参见教材相关章节,这里不再赘述。
// 构建哈夫曼树T完成后,再利用此树进行深度优先搜索,获得各字符(叶节点)的哈夫曼编码。
procedure enc_WriteToFile(HFMFileName: string);
// 将哈夫曼树相关信息和编码后的文件数据写入以HFMFileName为文件名的文件中。
// 输入的信息包含本程序所生成的压缩文件独有标识,以便于解码时检验文件合法性。
procedure TZipForm.Button2Click(Sender: TObject); // Compress
// 主窗体上“压缩”按钮的单击事件。
// 在此处执行输入合法性检验、文件覆盖确认等操作处理,并通过源文件名获取HFMFileName。
// 若源文件名为abc.txt,则经处理之后得到HFMFileName为abc.hfm。
(3)
解压模块
procedure dec_DecodeHFMFile(HFMFileName: string; ExtractedFileName: string);
// 将文件HFMFileName解码,将解码后的信息写入文件ExtractedFileName中。
// 首先检查待解码文件中是否包含本程序所独有的标识。如有才能执行解码操作,否则提示错误。
// 本过程主要包含读取待解码文件中的哈夫曼树和解开哈夫曼编码两步操作。
(4)
编码文件格式
- 默认文件后缀名为.hfm
- 文件的前三个字节为’hfm’。用于检验此文件是否为合法生成的哈夫曼编码文件。
- 接下来两个字节是一个ShortInt整数,记录源文件的字符数量(以下用n表示)。
- 再以后是n组哈夫曼编码数据。每一组的构成为:原字符 + 编码长度 + 编码。其中编码每8位占据一个字节,多余位数用0填补。
- 然后是编码内容正文。每8位以一个字节的方式存储。同样的,文件末端多余位数补0。
- 文件的末尾一个字节为编码内容正文末端的补0数目。
【细节说明】
由于程序代码过长,这里不直接贴出源代码,仅将程序中一些细节上的实现作简单的解释如下:
(1)
文件合法性校验
点击压缩按钮或解压按钮时,会首先作文件合法性校验。
根据待