实验原理:
1.Huffman编码
Huffman编码是一种无失真的编码方式,是可变字长编码(VLC)的一种。
Huffman编码基于信源的概率统计模型,它的基本思路是:
出现概率大的信源符号编长码,出现概率小的信源符号编短码,从而使平均码长最小。
在程序实现时常使用一种叫树的数据结构实现Huffman编码,由它编出的码是即时码。
2.本实验中Huffman编码的算法
(1)将文件以ASCII字符流的形式读入,统计每个符号出现的频率;
(2)将所有文件中出现的字符按照频率从小到大的顺序排列;
(3)每一次选频率最小的两个值,作为二叉树的两个叶子节点,将和作为它们的父节点,这两个叶子节点不再参与比较,新的父节点参与比较;
(4)重复步骤(3),直到最后得到频率和为1的根结点;
(5)将形成的二叉树的左节点标0,右节点标1,把从最上面的根节点到最下面的叶子节点图中遇到的0、1序列串起来,得到各个字符的编码表示;
3.Huffman编码的数据结构表示
在程序实现中使用一种叫做二叉树的数据结构实现Huffman编码。
(1)Huffman节点结构
typedef struct huffman_node_tag
{
unsigned char isLeaf;//判断是否为树叶节点
unsigned long count;//节点表示的符号出现的次数
struct huffman_node_tag *parent;//该节点的父节点指针
union//共用体,该节点代表一个信源符号或者拥有左右子节点
{
struct
{
struct huffman_node_tag *zero, *one;//左右子节点指针,编码时左为0右为1
};
unsigned char symbol;//信源符号
};
} huffman_node;
(2)Huffman编码的数据结构
typedef struct huffman_code_tag
{
unsigned long numbits;//码长(比特表示)
/* 码字,码字的第1位存于bits[0]的第1位 ,
码字的第2位存于bits[0]的第2位,
码字的第8位存于bits[0]的第8位,
码字的第9位存于bits[1]的第1位*/
unsigned char *bits;//指向该码字比特串的指针
} huffman_code;
(3)Huffman编码的统计结果
typedef struct huffman_statistics_result
{
float freq[256];//每个信源符号出现频率
unsigned long numbits[256];//码长
unsigned char bits[256][100];//码字
}huffman_stat;
Ps:上述三个结构体的创建均在下图(Huffman编码工程目录)的huffman.c文件中实现。
实验流程分析:
Huffman编码流程框图:
关键代码分析:
主函数(huffcode.c)中主要步骤分析:
/*step1: 创建和初始化文件读入、输出、表格文件输出指针及其他参数*/
main(int argc, char** argv)
{
char memory = 0;
char compress = 1;//编码为1解码为0
int opt;//将从命令行读取的数据赋值给opt
const char *file_in = NULL, *file_out = NULL;//输入输出文件指针
//step1:add by yzhang for huffman statistics
const char *file_out_table = NULL;//表格文件
//end by yzhang
FILE *in = stdin;//定义指向输入缓冲区的文件指针
FILE *out = stdout;//定义指向输出缓冲区的文件指针
//step1:add by yzhang for huffman statistics
FILE * outTable = NULL;//输出统计数据文件
//end by yzhang
/* step2:调用getopt函数获取和解析命令行参数 */
while((opt = getopt(argc, argv, "i:o:cdhvmt:")) != -1) //演示如何跳出循环,及查找括号对;当读取非空
{
switch(opt)
{
case 'i':
file_in = optarg;//optarg指向i额外的参数
break;
case 'o':
file_out = optarg;
break;
case 'c':
compress = 1;//设置为编码
break;
case 'd':
compress = 0;//设置为解码
break;
case 'h':
usage(stdout);//帮助显示使用方法
return 0;
case 'v':
version(stdout);//输出版本信息
return 0;
case 'm':
memory = 1;//改变内存中的值
break;
// by yzhang for huffman statistics
case 't'://输出数据统计文件
file_out_table = optarg;
break;
//end by yzhang
default:
usage(stderr);//如果是其他情况,则将使用方法信息送到标准错误文件
return 1;
}
}
/* step3:打开输入输出文件 */
if(file_in)
{
in = fopen(file_in, "rb");
if(!in)
{
fprintf(stderr,
"Can't open input file '%s': %s\n",
file_in, strerror(errno));
return 1;
}
}
if(file_out)
{
out