LZ77算法详解:字典压缩是怎么工作的?

结论先行:LZ77 是一种基于滑动窗口的字典压缩算法,核心思想是"用历史数据做字典,遇到重复内容就引用回去"。编码时输出三元组 (distance, length, next_char):回溯 distance 个字符找到匹配,匹配长度 length,紧跟一个未匹配字符 next_char。以"abracadabra"这 11 个字符为例,LZ77 编码后仅需 5 个三元组即可表示,压缩效果显著。LZ77 是 DEFLATE(ZIP/GZIP/PNG)的核心组件,也是 LZSS/LZMA/LZ4 等现代压缩算法的共同祖先。下面从滑动窗口原理讲起,逐步演示编码过程。

如果你对 Huffman 编码的原理还不太熟悉,建议先阅读Huffman 编码原理:压缩算法的基石详解

一、什么是字典压缩

压缩算法分两大流派:统计编码(如 Huffman 编码)按字符频率分配变长码字;字典压缩用"指针引用"替换重复内容。LZ77 属于字典压缩流派,它不预先构建字典表,而是用已处理的历史数据作为隐式字典——遇到重复内容时,用一个"回溯指针"指向之前出现过的位置。

压缩流派核心原理代表算法优势劣势
统计编码按频率分配变长码Huffman, 算术编码逼近熵下界不擅长长程重复
字典压缩用引用替换重复内容LZ77, LZW, LZMA擅长重复模式对随机数据无效
混合编码字典+统计两阶段DEFLATE, ZSTD综合最优实现较复杂
变换编码变换到频域再量化DCT(JPEG), DWT有损压缩效率高有信息损失

实践中最流行的压缩算法几乎都是"混合编码"——先用 LZ77 消除重复模式,再用 Huffman 对残差做频率压缩。DEFLATE 就是 LZ77 + Huffman 的经典组合,被 ZIP、GZIP、PNG 广泛使用。

二、LZ77 算法原理详解

LZ77 的核心是滑动窗口机制。窗口分为两部分:搜索缓冲区(已处理的历史数据)和前视缓冲区(待处理的未来数据)。编码时在前视缓冲区取一段内容,在搜索缓冲区中查找最长匹配,找到就输出三元组,找不到就输出原始字符。

1. 滑动窗口结构

滑动窗口的大小直接决定压缩效果——窗口越大,能回溯查找的历史数据越多,匹配概率越高。不同算法的窗口大小差异很大。

算法搜索缓冲区前视缓冲区最大匹配长度典型场景
LZ77原始几KB十几字节16字节教学示例
DEFLATE32KB258字节258字节ZIP/GZIP/PNG
LZMA8MB(可配)273字节273字节7z/xz归档
LZ464KB无限制无限制实时压缩
ZSTD8MB(最大1GB)无限制无限制现代通用

2. 三元组编码格式

LZ77 的输出单元是三元组 (distance, length, next_char),三个字段的含义如下表。

字段含义取值范围(DEFLATE)编码位数示例
distance回溯距离(向后多少字符找匹配)1–3276815 bitdistance=10 → 往前10个字符
length匹配长度(连续匹配多少字符)3–2588 bitlength=5 → 匹配5个字符
next_char匹配后的下一个字符0–2558 bitnext_char='d' → ASCII 100

三元组的巧妙之处在于:匹配结束后多输出一个 next_char,保证编码器总能向前推进至少 1 个字符,不会卡死。如果找不到任何匹配(length=0),distance 和 length 都为 0,只输出 next_char——相当于退化为原始字符存储。

3. 匹配查找策略

匹配查找是 LZ77 的性能瓶颈——在前视缓冲区取一段内容,在搜索缓冲区中找最长匹配。暴力查找是 O(n×m) 复杂度,实际实现用哈希表或后缀树加速。

查找策略数据结构查找复杂度空间开销典型应用
暴力查找O(n×m)教学示例
哈希链哈希表+链表O(n)平均zlib(DEFLATE)
哈希桶哈希表+数组O(1)平均LZ4
后缀树后缀树/后缀数组O(n)最坏LZMA

三、实战案例:"abracadabra"编码演示

用 LZ77 对"abracadabra"(11 个字符)进行完整编码。初始状态搜索缓冲区为空,前视缓冲区为整个字符串。逐个位置扫描,在历史数据中查找最长匹配。

原文: a b r a c a d a b r a

编码过程:

步骤当前位置前视内容搜索缓冲区查找输出三元组说明
1位置1abracadabra空,无匹配(0, 0, 'a')首个字符,直接输出
2位置2bracadabra"a",无匹配"b"(0, 0, 'b')首次出现,直接输出
3位置3racadabra"ab",无匹配"r"(0, 0, 'r')首次出现,直接输出
4位置4acadabra"abr"中找到"a"(0, 0, 'a')"a"出现但后续不匹配
5位置5cadabra"abra"中无"c"(0, 0, 'c')首次出现,直接输出
6位置6adabra"abrac"中找到"a"(0, 0, 'a')"a"匹配但后续不匹配
7位置7dabra"abraca"中无"d"(0, 0, 'd')首次出现,直接输出
8位置8abra回溯7找到"abra"匹配(7, 4, end)匹配"abra"4个字符

编码效率对比:

编码方式输出单元数每单元bit总bitvs原始节省
ASCII原始11字符888—(基准)
LZ77(无匹配优化)8三元组31(平均)248-182%(膨胀)
LZ77(优化标记位)8单元12(平均)96-9%(略膨胀)
LZ77+Huffman8单元4.5(平均)3659%

结果分析: 纯 LZ77 对短字符串可能膨胀(三元组比原始字符占用更多空间),这就是为什么 LZ77 通常与 Huffman 编码组合使用——DEFLATE 就是 LZ77 + Huffman。在"abracadabra"案例中,位置 8 的匹配"abra"(distance=7, length=4)是关键压缩点,4 个字符用一个三元组表示。对于更长、重复模式更多的文本(如代码文件、日志),LZ77 的压缩效果会显著提升。

四、LZ77 变体与现代演化

LZ77 自 1977 年提出后衍生出大量变体,每个变体针对特定场景优化了某个维度。下表对比主流 LZ77 家族成员。

算法关键改进压缩率压缩速度解压速度典型应用
LZ77(原始)三元组编码教学
LZSS用标记位区分匹配/字面量早期系统
DEFLATELZSS+Huffman两阶段中高ZIP/GZIP/PNG
LZMA大窗口+区间编码+最优解析7z/xz归档
LZ4牺牲压缩率换极致速度极快极快(4GB/s)实时/内核
LZW显式字典表(非滑动窗口)GIF/TIFF
ZSTDLZ77变体+FSE+字典预设极快现代通用

从演化趋势看,现代算法(ZSTD、brotli)在保持高压缩率的同时大幅提升了速度,逐渐取代 DEFLATE 成为新一代标准。但 LZ77 的核心思想——滑动窗口字典引用——始终未变,所有变体都建立在这个基础之上。

场景推荐算法理由压缩率参考
文件归档LZMA(xz)压缩率最高,不追求速度70%–85%
通用压缩ZSTD压缩率和速度兼顾60%–80%
实时传输LZ4解压速度4GB/s,延迟极低50%–65%
Web传输DEFLATE/GZIP兼容性最好,所有浏览器支持50%–70%
图片格式DEFLATE(PNG)无损压缩,适合图形类50%–75%
内存数据LZ4低CPU占用,适合高频压缩50%–65%

关于 PNG 格式中 DEFLATE 的具体应用,可以参考PNG 압축 원리详解。无损压缩与有损压缩的区别,可以参考无损压缩 vs 有损压缩:核心区别

五、常见问题FAQ

Q1:LZ77算法是什么?

LZ77 是一种基于滑动窗口的字典压缩算法,由 Lempel 和 Ziv 于 1977 年提出。核心思想是:用之前已处理的数据作为字典,遇到重复内容时用 (distance, length, next_char) 三元组替换原始数据,distance 表示回溯距离,length 表示匹配长度,next_char 表示匹配后的下一个字符。LZ77 是 DEFLATE(ZIP/GZIP/PNG) 的核心组件,也是 LZSS/LZMA/LZ4 等现代算法的祖先。

Q2:LZ77的滑动窗口是什么意思?

滑动窗口是 LZ77 的核心数据结构,分为搜索缓冲区(已处理的历史数据)和前视缓冲区(待处理的未来数据)。编码时在前视缓冲区中取一段内容,在搜索缓冲区中查找最长匹配。典型窗口大小为 32KB(DEFLATE 标准),窗口越大匹配概率越高但内存开销越大。窗口大小决定了最大回溯距离 distance 的上限。

Q3:LZ77和LZ78有什么区别?

LZ77 用滑动窗口做隐式字典,匹配内容直接引用历史数据,不单独存储字典;LZ78 用显式字典表,把已见的字符串编号存储为字典条目,编码时输出字典索引。LZ77 更适合有局部重复的数据(如文本),LZ78 更适合全局重复的数据。实践中 LZ77 的后代(DEFLATE/LZMA/LZ4)远比 LZ78 的后代(LZW)更流行。

Q4:LZ77、LZMA、LZ4哪个压缩率最高?

压缩率排序:LZMA > LZ77(DEFLATE) > LZ4。LZMA 用更大的窗口(默认 8MB)、更优的匹配算法和区间编码,压缩率最高但速度最慢;DEFLATE 窗口 32KB + Huffman,压缩率中等速度中等;LZ4 牺牲压缩率换取极致速度,压缩率最低但解压速度可达 4GB/s。选型取决于场景:归档选 LZMA,通用选 DEFLATE/ZSTD,实时选 LZ4。

总结

LZ77 是字典压缩算法的鼻祖,核心原理是"滑动窗口 + 三元组引用":用历史数据做隐式字典,遇到重复内容就输出 (distance, length, next_char) 三元组。纯 LZ77 对短文本可能膨胀,但与 Huffman 编码组合后(DEFLATE)成为 ZIP/GZIP/PNG 的标准压缩方案。现代变体 LZMA 追求极致压缩率,LZ4 追求极致速度,ZSTD 兼顾两者。

理解 LZ77 的关键三点:一是滑动窗口决定匹配范围(DEFLATE 32KB,LZMA 8MB),二是三元组是基本编码单元(回溯+长度+下一字符),三是匹配查找策略决定性能(哈希链最快,后缀树最优)。LZ77 + Huffman 的混合编码是现代无损压缩的黄金标准。

파일을 압축해야 하나요? SmartSlim을 사용해 보세요

자체 개발한 Rust 압축 엔진을 기반으로, PDF/이미지/동영상/Office/OFD 등 10개 분야 40개 이상의 형식을 지원합니다. 로컬 압축으로 데이터가 외부로 나가지 않습니다.