简述

  LZ77是以色列计算机科学家Abraham Lempel与 Jacob 在1977 年发表之论文中的无损数据压缩算法。是大多数LZ算法变体如LZW、LZSS以及其它一些压缩算法的基础。

LZ77

定义

  此过程将字符串 $S[1\ldots{n}]$ 分解为非空元素集合 $\{w_1,w_2,\ldots,w_k\}$,对于 $w_i$,有两者可能:

  1. 一个新字符,$w_i\in{S[1\ldots{n}]}$ 且 $w_i\not\in{S[1\ldots{n-1}]}$
  2. $w_i$ 是 $\{w_1,\ldots,w_i\}$ 中出现至少两次的最长子串

  $w_i$ 被称为因子或短语
  $S[i\ldots{j}]$ 表示位置 $i$ 到 $j$ 的子串,$S[i]$ 是 $i$ 处的字符

算法

  计算 LZ77 压缩的算法核心思想是将已处理的字符串用作字典。为了限制搜索时间,实际应用中通常限制字典的大小,因此通常使用滑动窗口(sliding window)。滑动窗口被分割为字典区和预览缓冲区。压缩过程中,字符逐步从预览缓冲区移动到字典中。实际应用中,字典缓冲区通常包含数千个字符,而预览缓冲区则包含约100个字符或更少。
  算法输出由三元组组成,可以用来恢复原始文本。对于因子 $w_i$ 的三元组形式为 $(pos,len,\lambda)$:

压缩算法

  以字符串 $aacaacabcabaaac$ 为例说明 LZ77 压缩的计算过程,算法采用字典长度为12(紫色区域)和预览缓冲区(黄色区域)长度为10的滑动窗口模型。算法输出的三元组包括:

  以下是算法过程演示:

LZ77

解压算法

  解压算法相较于压缩算法更加简单,其运行时间为 $O(n)$,对当前长度为 $n$ 字符串 $S$,迭代元组序列且对于任意元组 $(pos,len,\lambda)$:

无滑动窗LZ77

  此方法无需使用滑动窗来计算所需元组,它的方法是:

  1. 设待压缩长为 $n$ 字符串为 $S$ 且 $S_x$ 为 $S[x\ldots{n}]$ 后缀。
  2. 要计算字符串在 $k$ 位置对应的元组,需要找到最接近的 $S_i$、$S_j$ 且满足 $S_i<S_k,i\lt{k}$、$S_j>S_k,j\lt{k}$,然后计算 $(S_i, S_k)$ 和 $(S_j, S_k)$ 的最长公共前缀,从两个结果中选择较长的一项作为最长公共子串。
  3. 这个算法的思想是:两个后缀的字典序大小越接近,则它们的公共前缀越长,此方法是从 $k$ 处向前寻找最长公共子串。