LZ77算法 的分析与实现(2)

用LZ77算法压缩数据是非常耗时的,国为要花很多时间寻找窗口中的匹配短语。然而在通常情况下,LZ77的解压缩过程要比霍夫曼编码的解压缩过程耗时要少。LZ77的解压缩过程非常快是因为每个标记都明确地告诉我们在缓冲区中哪个位置可以读取到所需要的符号。事实上,我们最终只从滑动窗口中读取了与原始数据数量相等的符号而已。

LZ77的接口定义

lz77_compress

int lz77_compress(const unsigned char *original, unsigned char **compressed, int size);

返回值:如果数据压缩成功,返回压缩后数据的字节数;否则返回-1;

描述:  用LZ77算法压缩缓冲区original中的数据,original包含size个字节的空间。压缩后的数据存入缓冲区compressed中。lz77_compress需要调用malloc来动态的为compressed分配存储空间,当这块空间不再使用时,由调用者调用函数free来释放空间。

复杂度:O(n),其中n是原始数据中符号的个数。

lz77_uncompress

int lz77_uncompress(const unsigned char *compressed, unsigned char **original);

返回值:如果解压缩数据成功,返回恢复后数据的字节数;否则返回-1;

描述:  用LZ77算法解压缩缓冲区compressed中的数据。假定缓冲区包含的数据之前由lz77_compress压缩。恢复后的数据存入缓冲区original中。lz77_uncompress函数调用malloc来动态的为original分配存储空间。当这块存储空间不再使用时,由调用者调用函数free来释放空间。

复杂度:O(n)其中n是原始数据中符号的个数。

LZ77的实现与分析

LZ77算法,通过一个滑动窗口将前向缓冲区中的短语编码成相应的标记,从而达到压缩的目的。在解压缩的过程中,将每个标记解码成短语或符号本身。要做到这些,必须要不断地更新窗口,这样,在压缩过程中的任何时刻,窗口都能按照规则进行编码。在本节所有的示例中,原始数据中的一个符号占一个字节。

lz77_compress

lz77_compress操作使用LZ77算法来压缩数据。首先,它将数据中的符号写入压缩数据的缓冲区中,并同时初始化滑动窗口和前向缓冲区。随后,前向缓冲区将用来加载符号。

压缩发生在一个循环中,循环会持续迭代直到处理完所有符号。使用ipos来保存原始数据中正在处理的当前字节,并用opos来保存向压缩数据缓冲区写入的当前位。在循环的每次迭代中,调用compare_win来确定前向缓冲区与滑动窗口中匹配的最长短语。函数compare_win返回最长匹配串的长度。

当找到一个匹配串时,compare_win设置offset为滑动窗口中匹配串的位置,同时设置next为前向缓冲区中匹配串后一位的符号。在这种情况下,向压缩数据中写入一个短语标记(如图3-a)。在本节展示的实现中,对于偏移量offset短语标记需要12位,这是因为滑动窗口的大小为4KB(4096字节)。此时短语标志需要5位来表示长度,因为在一个32字节的前向缓冲区中,不会有匹配串超过这个长度。当没有找到匹配串时,compare_win返回,并且设置next为前向缓冲区起始处未匹配的符号。在这种情况下,向压缩数据中写入一个符号(如图3-b)。无论向压缩数据中写入的是一个短语还是一个符号,在实际写入标记之前,都需要调用网络函数htonl来转换串,以保证标记是大端格式。这种格式是在实际压缩数据和解压缩数据时所要求的。

LZ77算法 的分析与实现

图3:LZ77中的短语标记(A)和符号标记(B)的结构

一旦将相应的标记写入压缩数据的缓冲区中,就调整滑动窗口和前向缓冲区。要使数据通过滑动窗口,将数据从右边滑入窗口,从左边滑出窗口。同样,在前向缓冲区中也是相同的滑动过程。移动的字节数与标记中编码的字符数相等。

lz77_compress的时间复杂度为O(n),其中n是原始数据中符号的个数。这是因为,对于数据中每个n/c个编码的标记,其中1/c是一个代表编码效率的常量因素,调用一次compare_win。函数compare_win运行一段固定的时间,因为滑动窗口和前向缓冲区的大小均为常数。然而,这些常量比较大,会对lz77_compress的总体运行时间产生较大的影响。所以,lz77_compress的时间复杂度是O(n),但其实际的复杂度会受其常量因子的影响。这就解释了为什么在用lz77进行数据压缩时速度非常慢。

lz77_uncompress

lz77_uncompress操作解压缩由lz77_compress压缩的数据。首先,该函数从压缩数据中读取字符,并初始化滑动窗口和前向缓冲区。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/63ea8e8e21f6166bd56ddba031d50800.html