哈夫曼(huffman)解码用查表法,数据组织采用树形结构,若采用二叉树,一次处理一位(bit),效率是比较低的。从一些杂志上看到关于哈夫曼(huffman)解码的快速算法介绍,直接用位流索引一次处理N(4<N<=32)位,这种方法实际上是不可行的,原因是构造出的码表很长,如果一次处理8位,可以编写程序构造出码表,不过可以肯定的是码表的长度会超过我们事先的想象,以至于没有多大的实用价值。一次处理多位(一位以上)码表中冗余度很大导致码表很长。
MP3解码处理主数据(main_data)的第一步就是对主数据进行哈夫曼解码。MP3编解码用到的哈夫曼表由ISO/IEC 11172-3 的附录B中给出,大值区用到31张码表(其中第0、4、14号码表未使用),小值区用到两张码表。从ISO/IEC 11172-3复制出两张原始的码表来分析,解码大值区的码表:
Huffman code table 7
x y hlen hcod
0 0 1 1
0 1 3 010
0 2 6 001010
0 3 8 00010011
0 4 8 00010000
0 5 9 000001010
1 0 3 011
1 1 4 0011
1 2 6 000111
1 3 7 0001010
1 4 7 0000101
1 5 8 00000011
2 0 6 001011
2 1 5 00100
2 2 7 0001101
2 3 8 00010001
2 4 8 00001000
2 5 9 000000100
3 0 7 0001100
3 1 7 0001011
3 2 8 00010010
3 3 9 000001111
3 4 9 000001011
3 5 9 000000010
4 0 7 0000111
4 1 7 0000110
4 2 8 00001001
4 3 9 000001110
4 4 9 000000011
4 5 10 0000000001
5 0 8 00000110
5 1 8 00000100
5 2 9 000000101
5 3 10 0000000011
5 4 10 0000000010
5 5 10 0000000000
解码小值区的码表:
Huffman code table 17
x y hlen hcod
0 0 1 1
0 1 4 0101
0 2 4 0100
0 3 5 00101
0 4 4 0110
0 5 6 000101
0 6 5 00100
0 7 6 000100
0 8 4 0111
0 9 5 00011
0 10 5 00110
0 11 6 000000
0 12 5 00111
0 13 6 000010
0 14 6 000011
0 15 6 000001
所有码表中,大值区的x=0..15,y=0..15,码长hlen=1..19。
一次处理多位应该如何实现呢?首先构造出码表,如果每次处理2比特,构造码表暂存数据时用4叉树;如果一次处理3比特,则用8叉树,以此类推。编程从一个文本文件中读入如上所示的原始的哈夫曼表数据,将其插入到N叉树中相应的位置。假如一次处理2位而码字(hcod)是5位(hlen=5),那么在hcod最后分别补上0和1凑足2的整数倍位数,这就导致了构造出的哈夫曼表冗余度,即一个码字对应多个码表中元素。一次处理的位数越多,构造出的码表的冗余度越大。
根据自己解码设计构造出码比较费事,解码过程挺简单。
实际编程中,可以用数组来存储N叉树,只需要将指针域的值改为元素在数组中的下标值。以大值区解码一次处理2比特为例,x和y取值范围为0..15,只需占用4比特;码长hlen取值范围为1..19,存储hlen只需5比特。存储一个码值只需要13比特,可以将一个码值存储在16位整数中,低4位是y,接下来的4位是x,再接下来的5位是hlen。高3位全为零表示该数组元素存储的是一个码值,最高位为1(表示负数)则其绝对什表示该数组元素存储的是数组的下标值。经过这样处理后解码大值区的码表“Huffman code table 7”:
static short htbv7[72] = {
-4, -68, 256, 256, -8, -48, -64,1041, -12, -28, -40, -44, -16, -20, -24,2069,
2645,2629,2644,2643,2357,2357,2372,2372,2341,2341,2386,2386,2129, -32,2128, -36,
2309,2309,2356,2356,2371,2371,2355,2355,2084,2114,1812,1812,1857,1857,1856,1856,
-52, -56, -60,1554,2052,2083,2098,2051,1811,1811,1841,1841,1840,1840,1826,1826,
1313,1313,1538,1568, 769, 769, 784, 784};
解码小值区的码表“Huffman code table 17”一次处理4比特:
static short htc0[80] = {
-16, -32, -48, -64,1026,1025,1028,1032, 256, 256, 256, 256, 256, 256, 256, 256,
1547,1547,1547,1547,1551,1551,1551,1551,1549,1549,1549,1549,1550,1550,1550,1550,
1543,1543,1543,1543,1541,1541,1541,1541,1289,1289,1289,1289,1289,1289,1289,1289,
1286,1286,1286,1286,1286,1286,1286,1286,1283,1283,1283,1283,1283,1283,1283,1283,
1290,1290,1290,1290,1290,1290,1290,1290,1292,1292,1292,1292,1292,1292,1292,1292};
码表构造好了,如何解码呢?从码流中读入4字节暂存到unsigned int umask,解码大值区得到x和y:
y = ptab[umask >> 30]; // 一次处理2比特,ptab指向码表(如ptab=htbv7)
while (y < 0) {
umask <<= 2;
y = ptab[(umask >> 30) - y];
}
x = y >> 8; // hlen
num -= x; // num为umask中剩余的比特数
umask <<= x;
x = (y >> 4) & 0xf; // 得到x值
y &= 0xf; // 得到y值
解码小值区得到y值的代码:
y = ptab[umask >> 28]; // 一次处理4比特
while (y < 0) {
umask <<= 4;
y = ptab[(umask >> 28) - y];
}
x = y >> 8; // hlen
num -= x;
umask <<= x;
y &= 0xf; // 得到y值
每解码完一个码字,重新刷新umask和num。以上解码方法正确与否可以用“Huffman code table 7”或“Huffman code table 17”内的数据去检查。
一次处理N比特肯定比一次处理1比特效率高。兼顾效率和存储空间开销,解码大值区采用一次处理2位到4位,解码小值区一次处理4位,这样比较好。
分享到:
相关推荐
### MP3解码算法原理详解 #### 一、概述 MP3作为一种广泛使用的音频压缩格式,其高效的数据压缩技术使其成为数字音乐领域的标准之一。本文将深入探讨MP3解码的具体算法及其工作原理,帮助读者更好地理解MP3格式的...
相反,将编码还原成原始数据的过程被称为哈夫曼解码。 在C语言中实现哈夫曼编码和解码,通常包括以下步骤: 1. **构建哈夫曼树**:首先统计字符的出现频率,然后根据频率创建一个优先队列(通常用最小堆实现)。...
哈夫曼编码是一种高效的数据压缩方法,由大卫·哈夫曼在...MATLAB作为强大的科学计算工具,提供了丰富的函数支持,使得在其中实现哈夫曼编解码变得相对简单。通过学习和实践,你可以更好地掌握这一重要的数据压缩算法。
它可能调用了其他子函数,如解析MP3帧头、解密音频数据块、执行哈夫曼解码等。 `common.c`:通用功能模块,通常包含了跨文件使用的辅助函数,比如内存管理、错误处理或数据类型转换等。 `musicout.c`:这个名字...
利用C++实现哈夫曼算法 哈夫曼算法是数据压缩的一种重要算法,它的主要思想是构造一棵哈夫曼树(二叉树),其基本思路是,每次从字符中挑出两个...同时,哈夫曼算法也可以应用于其他领域,如数据压缩、编码和解码等。
3. **哈夫曼解码** - 给定一个已编码的字符串,从根节点开始,根据遇到的0和1沿着哈夫曼树向下移动。当到达叶子节点时,读取对应的符号,然后返回根节点,继续解码剩余的编码。 在C++中实现哈夫曼编码和解码,需要...
- MATLAB是一种强大的数学计算和数据可视化工具,它的优点在于能够快速原型开发和实验。在MATLAB中,可以使用内置的数据结构和函数来实现哈夫曼树的构建和编码过程。例如,可以使用队列和树节点结构来表示哈夫曼树...
总结起来,这个压缩包提供了哈夫曼编码和解码的实现,对于学习数据结构和算法,尤其是理解和应用变长编码技术,是非常有价值的资源。通过对它的研究,不仅可以掌握哈夫曼编码的基本原理,还能了解如何将理论知识应用...
在C语言中实现哈夫曼编码与解码的过程包括几个关键步骤:构造哈夫曼树、生成哈夫曼编码、编码文件和解码文件。 1. 构造哈夫曼树: - 首先,统计输入文本中每个字符出现的频率。 - 然后,创建一个最小堆(优先队列...
例如,哈夫曼树的构建和遍历应尽可能快,哈夫曼编码和解码的过程也要避免不必要的计算。 通过以上步骤,我们可以构建出一个完整的哈夫曼编码解码器。在实际应用中,这个工具可以用于压缩文本、图像等数据,减少存储...
哈夫曼树(Huffman Tree),也称为最优二叉树,是数据压缩中的一种关键算法。在C#中实现哈夫曼编码和解码程序,主要是为了高效地进行数据的压缩与解压缩操作。哈夫曼编码利用了字符出现频率的不同,为频率高的字符...
哈夫曼解码则相反,它是从编码反向推导出原始字符的过程: 1. **读取编码**:按照编码的位序列,从根节点出发,根据遇到的0和1选择相应的分支。 2. **到达叶节点**:当所有编码位都被读取,或者到达叶节点时,识别出...
3. **构造哈夫曼树**:根据频率数组,使用贪心算法构建哈夫曼树。可以维护两个优先队列,一个用于存储待合并的节点,另一个用于存储已生成的节点。每次从队列中取出频率最小的两个节点合并,然后将新生成的节点加入...
在给定的“哈弗曼编码”文件中,可能包含了实现哈夫曼编码和解码的具体算法和源代码。这些代码可能包括了创建哈夫曼树的函数、生成编码表的函数、解码函数,以及与用户交互的界面逻辑。通过阅读和理解这些代码,可以...
C语言 哈夫曼树的编码解码
但是,哈夫曼算法也存在一些缺点,例如编码和解码的时间复杂度较高,且不适合实时处理的大数据量。 本实验报告展示了哈夫曼算法的设计和实现,并对其进行了分析。哈夫曼算法是数据压缩领域中的一个重要算法,具有...
- 实验目的:理解哈夫曼编码的原理,掌握编码和解码算法。 - 设计思路:如何设计数据结构(如优先队列、哈夫曼树)来实现编码和解码。 - 模块解释:各个函数的作用和工作流程。 - 结果分析:编码前后的文件大小比较...
这个程序包括了编码和解码两个过程,可以从`in.bmp`输入图像,通过`Compressor.cpp`中的算法进行压缩,将结果保存到`encode.dat`文件中,然后通过解码过程生成`out.bmp`。让我们详细探讨一下这个过程。 1. **哈夫曼...
在编码过程中,会读取这些文本文件,计算每个字符的频率,构建霍夫曼树,生成编码表,并将文本转换为霍夫曼编码的二进制流。解码时,则会读取这个二进制流,按照霍夫曼树进行反向操作,恢复出原始文本。 在实际应用...
在本文中,我们将深入探讨哈夫曼算法的原理、编码与解码过程,并结合提供的源代码文件`Huffman.cpp`和`Huffman.h`进行分析。 **哈夫曼编码原理** 哈夫曼编码是基于频率的变长编码,它通过构建一个二叉树来为每个...