算法#19--霍夫曼压缩(数据压缩)

本文详细介绍了霍夫曼编码的概念,包括前缀码的定义、霍夫曼单词查找树的构建过程,以及数据压缩和解压的原理。通过构建霍夫曼树,实现了对字符出现频率的优化编码,从而实现更高效的数据压缩。同时,文章还提供了压缩和解压的步骤说明。

定义

我们现在来学习一种能够大幅压缩自然语言文件空间(以及许多其他类型文件)的数据压缩技术。

它的主要思想是放弃文本文件的普通保存方式:不在使用7位或8位二进制数表示每一个字符,而是用较少的比特表示出现频率高的字符,用较多的比特表示出现频率低的字符。

简而言之,不在用ASCII编码表示,而是用较短的前缀码表示。

前缀码

什么是前缀码?如果所有字符编码都不会成为其他字符编码的前缀,符合这种规则的叫前缀码。

比如,如果A的编码为0,R的编码为00,那么A的编码是R的前缀,这不属于前缀码。那么前缀码的例子是什么样的呢?如下:

所有的前缀码的解码方式都和它一样,是唯一的。因此前缀码被广泛应用于实际生产中。注意,像7位ASCII编码编码这样的定长编码也是前缀码。

霍夫曼单词查找树

表示前缀码的一种简便方法就是使用单词查找树。

任意含有M个空链接的单词查找树都没M个字符定义了一种前缀码方法:我们将空链接替换为指向叶子结点(含有两个空链接的结点)的链接,每个叶子结点都含有一个需要编码的字符。这样,没个字符的编码都是从根结点到该结点的路径表示的比特字符串,其中左链接表示0,右链接表示1.

如果构造这样一棵树?

首先,树的结点包含left和right,和一个字符频率变量freq,以及字符ch。以下为构造一颗霍夫曼单词查找树的过程:

  1. 将需要被编码的字符放在叶子结点中并在每个结点中维护了一个名为freq的实例变量来表示以它为根结点的子树种的所有字符出现的频率。
  2. 创建一片由许多只有一个结点(即叶子结点)的树所组成的森林。每棵树都表示输入流的一个字符,每个结点中的freq表示它在输入流中的出现频率。
  3. 找到两个频率最小的结点,然后创建一个以二者为子结点的新结点(新结点的频率为它的两个子结点的频率之和)。
  4. 不断重复第3过程,最终所有的结点会被合并为一颗单独的单词查找树。

特点:

  • 树的叶子结点包含freq和字符。
  • 频率高的离根结点最近,频率低的在树的底层。
  • 根结点频率值等于输入中的字符数量。
  • 该树表示的编码压缩比其他树更多,是一种最优的前缀码

压缩

对于任意单词查找树,都能产生一张将树中的字符和比特字符串(用由0和1组成的String字符串表示)相对应的编译表。其实就是字符和它的比特字符串的符号表。在这里我们用st[]数字表示。在构造符号表时buildCode()递归遍历整棵树,并为每个结点维护一条从根结点到它的路径所对应的二进制字符串(左链接表示0,右链接表示1)。到达一个叶子结点后,就将结点的编码设为该二进制字符串。如下图的编译表:

然后,压缩就很简单了,只需要在其中找到输入字符所对应的编码即可。

上图字符串ABRACADABRA!的编码为:首先是0(A的编码),然后是111(B的编码),然后是110(R的编码),最后得到完整编码为0111110010110100011111001010.

解压

首先readTrie()将霍夫曼单词查找树编码为的比特流构造为霍夫曼查找树。然后读取霍夫曼压缩码,根据该编码从根结点向下移动(读取一个比特,为0移动到左结点,为1移动到右结点)。当遇到叶子结点后,输出该结点的字符并重新回到根结点。

例如压缩ABRACADABRA!后的编码为:0111110010110100011111001010,其单词查找树的比特流为:01010000010010100010001001000011010000110101010010101000010。

首先由树的比特流构造霍夫曼查找树(得如下树),然后解码编码。第一个为0,所以移动到左子结点,输出A;回到根,然后连续三个1,即向右移动3次,输出B;回到根,然后两个1,一个0,即向右移动两次,向左移动一次,输出R。如此重复,最后得到ABRACADABRA!

实现代码


/**
 * 霍夫曼压缩
 * @author nicholas.tang
 *
 */
public class Huffman 
{
    public static int R = 256;
    public static final int asciiLength = 8;//ascii码,一个字符等于8个bit
    public static String bitStreamOfTrie = "";
### MATLAB 中实现图像压缩算法的方法 #### 1. 理解图像压缩的基本概念 图像压缩旨在减少表示一幅图像所需的数据量,从而节省存储空间或传输带宽。主要分为有损压缩和无损压缩两种类型[^3]。 #### 2. 霍夫曼编码的应用 霍夫曼编码是一种经典的无损数据压缩方法,在MATLAB中可以通过构建频率表并生成相应的霍夫曼树来实现高效的编码过程[^2]。 #### 3. JPEG 图像压缩的具体实现 JPEG 是一种广泛应用的标准,支持可调节的质量参数以平衡文件大小与视觉效果之间的关系。下面是一个简单的基于离散余弦变换 (DCT) 的JPEG压缩实例: ```matlab function compressedImage = jpegCompress(inputImage, qualityFactor) % 将彩色图像转为灰度图 grayImg = rgb2gray(inputImage); % 应用 DCT 变换 dctMatrix = dctmtx(8); % 获取标准的 8x8 DCT 矩阵 blocks = blockproc(grayImg,[8 8], @(block_struct) ... double(dctMatrix * block_struct.data * dctMatrix')); % 定义量化矩阵,并应用量化操作 quantizationTable = getQuantizationTable(qualityFactor); quantizedBlocks = round(blocks ./ repmat(quantizationTable,... [size(blocks,1)/8 size(blocks,2)/8])); % 进行反向量化及 IDCT 转换恢复近似原图 reconstructedBlocks = blockproc(quantizedBlocks,[8 8],... @(block_struct) uint8(round(repmat(quantizationTable,... [size(block_struct.data,1)/8 size(block_struct.data,2)/8]) .* ... single(idctmtx(8)'*single(block_struct.data)*idctmtx(8))))); function qt = getQuantizationTable(qf) baseQt = [16 11 10 16 24 40 51 61; 12 12 14 19 26 58 60 55; 14 13 16 24 40 57 69 56; 14 17 22 29 51 87 80 62; 18 22 37 56 68 109 103 77; 24 35 55 64 81 104 113 92; 49 64 78 87 103 121 120 101; 72 92 95 98 112 100 103 99]; if qf >= 50 scale = floor((100-qf)/50*50+50); else scale = 5000/qf; end qt = max(min(floor(baseQt.*scale/100),255),1); end compressedImage = imresize(reconstructedBlocks,size(grayImg)); end ``` 此代码片段展示了如何利用MATLAB内置函数`dctmtx()`计算DCT系数以及自定义辅助函数完成整个流程中的各个步骤,包括但不限于颜色空间转换、分块处理、正交变换及其逆运算等[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值