数据压缩实验三:用c语言实现Huffman编码和压缩效率分析

本文介绍了使用C语言实现Huffman编码的实验,详细阐述了Huffman编码的原理、算法和数据结构。实验流程包括统计字符频率、建立Huffman树、生成编码、写入码表及编码文件。实验结果显示,Huffman编码适用于信源符号分布集中的文件,但在复杂文件中码表传输可能降低压缩效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验原理:

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 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值