一次一小步之用C++实现Huffman文件压缩

本文介绍了Huffman编码的基本原理,包括结点路径长、树的路径长度等概念,并详细阐述了如何使用C++实现Huffman文件压缩。通过构建最优的扩充二叉树,实现了信息压缩,降低了加权路长,达到压缩目的。文中还给出了编码和解码的具体步骤,以及部分源代码片段。

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

首先介绍下Huffman算法:


哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码。


明确几个概念:(主要来自高教出版的数据结构与算法,不想看的这里可以直接跳过,点这里

 

结点路径长:如果n1,n2,n3,...,nk是树中的节点序列,并且ni是ni+1(1=<i<=k-1)的父结点,这节点序列n1,n2,n3,...,nk称为n1~nk的一天路径,路径长度就是k-1个长度之和。

树的路径长度:从树的根到树中每一个结点的路径长度之和。

 

二叉树

如上图所示,假如每个相邻结点之间长度为1,从A到C之间的路径长度即为2

 

 

扩充二叉树:每当在原来的二叉树出现空子树时,就加上一个特殊的结点,如下图

 

外结点:上图方形的结点;

内结点:圆形的结点;

外路长:根结点到每个外节点的路长之和;

内路长:根结点到每个内结点的路长之和;

加权路长:设有m个实数w1,w2,w3,...,wm,构造一棵有m个外结点的扩充二叉树,并按一定的方法将数w1,w2,w3,...,wm与这m个外结点联系起来,称SUM(wjlj)为二叉树额加权路长,其中lj为某个外结点外路长,wj是与此结点相对应的实数,如上图的实数;

 

 

显然,上图的加权路长为2 * 3 + 1 * 3 + 3 * 2 + 6 * 3 + 7 * 4 + 4 * 4 + 5 * 3 + 8 * 3,但是,你发现了吗?将1、2和7、4的未知替换之后,加权路长会减少,对,我么离Huffman不远了。

 

现在,我们需要构造这样一棵二叉树,它的出现使我们有最小的加权路长,因而我们能用这个原理来压缩信息。

至于怎么用,且听我慢慢说来:

 

计算机里文件的最小单位是字节Byte,8位,采用等长编码,共256个码,于是我们将他们构成一颗二叉树,每个码都对应一个二叉树的叶结点,这棵树有511个结点,共9层。由于是等长编码,这棵二叉树的扩充二叉树的每个权值的大小相同,不妨定为1/256,于是,这颗扩充二叉树的加权路长为1/256*8*256=8,刚好是每个字节有的位数。但是,大家知道,文件中每个字符出现的频率是不一样的,比如26个字母的出现的频率不一致造成了你现在的键盘布局。

 

于是,我们不妨统计一下每个字符的频率,将频率作为上面提到的256个码扩充二叉树的权值,这样,只要通过一定的算法构造一课最优的扩充二叉树,我们就可以达到信息压缩的目的。

 

可能看得有点迷糊,不要紧,看下面的例子,顺便提下前缀性编码

 

假如一种信息由a,b,c,d组成,各字符出现的频率是0.12、0.4、0.15、0.33,用一个二进制数字串,对每个字符进行编码,使任意一个字符的编码不会是任何其他字符编码的前缀。通常把编码的这种特性佳作“前缀性”,“前缀性”使任意两个字符之间不需要加分隔符。

如上图所示,等长编码的编码长度为2(上面提到过,加权路长即为编码位数),而哈夫曼编码长度为:0.12 * 3 + 0.15 * 3 + 0.33 * 2 + 0.4 * 1 = 1.87,显然,我们达到了信息压缩的目的。

 

好了,说到这里,我们以256个数码(对应一个字节)为例,正式开始讲解Huffman算法:

1、给出256个数码的统计频率,即权值,构造具有256棵扩

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值