UGLYPEAR AI обновил бизнес: высокопроизводительное сжатие документов × RAG-платформа инженерии данныхУзнать о новом направлении →

Подробное объяснение алгоритма LZ77: как работает словарное сжатие?

Вывод вперёд: LZ77 — это алгоритм словарного сжатия на основе скользящего окна, основная идея которого — "использовать исторические данные как словарь, при обнаружении повторяющегося содержимого ссылаться на него". При кодировании выводится триплет (distance, length, next_char): обратный ход на distance символов для поиска совпадения, длина совпадения length, следующий несовпадающий символ next_char. На примере строки "abracadabra" из 11 символов, после кодирования LZ77 требуется всего 5 триплетов для представления, что даёт значительный эффект сжатия. LZ77 является ключевым компонентом DEFLATE (ZIP/GZIP/PNG) и общим предком современных алгоритмов сжатия LZSS/LZMA/LZ4. Ниже мы начнём с принципа скользящего окна и постепенно продемонстрируем процесс кодирования.

Если вы не очень знакомы с принципом кодирования Хаффмана, рекомендуется сначала прочитать Подробное объяснение принципа кодирования Хаффмана: основа алгоритмов сжатия.

1. Что такое словарное сжатие

Алгоритмы сжатия делятся на два основных направления: статистическое кодирование (например, кодирование Хаффмана) назначает символам коды переменной длины в соответствии с частотой; словарное сжатие заменяет повторяющееся содержимое "указателями-ссылками". LZ77 принадлежит к направлению словарного сжатия, он не создаёт заранее таблицу словаря, а использует уже обработанные исторические данные как неявный словарь — при обнаружении повторяющегося содержимого использует "указатель обратного хода" для ссылки на позицию, где оно ранее встречалось.

Направление сжатияОсновной принципПредставительные алгоритмыПреимуществаНедостатки
Статистическое кодированиеНазначение кодов переменной длины по частотеХаффман, арифметическое кодированиеПриближение к энтропийному пределуНе справляется с длинными повторами
Словарное сжатиеЗамена повторяющегося содержимого ссылкамиLZ77, LZW, LZMAХорошо справляется с повторяющимися шаблонамиНеэффективно для случайных данных
Гибридное кодированиеСловарь + статистика, два этапаDEFLATE, ZSTDОптимальное комбинированиеСложная реализация
Преобразующее кодированиеПреобразование в частотную область с квантованиемDCT(JPEG), DWTВысокая эффективность сжатия с потерямиПотеря информации

На практике самые популярные алгоритмы сжатия — это почти всегда "гибридное кодирование": сначала LZ77 устраняет повторяющиеся шаблоны, затем Хаффман выполняет частотное сжатие остатков. DEFLATE — это классическая комбинация LZ77 + Хаффмана, широко используемая в ZIP, GZIP, PNG.

2. Подробное объяснение принципа алгоритма 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

3. Практический пример: демонстрация кодирования "abracadabra"

Выполним полное кодирование строки "abracadabra" (11 символов) с помощью LZ77. Начальное состояние: буфер поиска пуст, буфер предварительного просмотра содержит всю строку. Посканируем позицию за позицией, ища самое длинное совпадение в исторических данных.

Исходный текст: a b r a c a d a b r a

Процесс кодирования:

ШагТекущая позицияСодержимое lookaheadПоиск в буфере поискаВыходной триплетОписание
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 символа

Сравнение эффективности кодирования:

Метод кодированияЧисло выходных единицБит на единицуВсего битЭкономия vs оригинала
ASCII оригинал11 символов888— (базовый)
LZ77 (без оптимизации)8 триплетов31 (ср.)248-182% (расширение)
LZ77 (оптимизация флагов)8 единиц12 (ср.)96-9% (лёгкое расширение)
LZ77 + Huffman8 единиц4,5 (ср.)3659%

Анализ результатов: чистый LZ77 для коротких строк может давать расширение (триплет занимает больше места, чем исходный символ) — именно поэтому LZ77 обычно комбинируют с кодированием Хаффмана; DEFLATE — это LZ77 + Huffman. В примере с "abracadabra" ключевая точка сжатия — позиция 8 с совпадением "abra" (distance=7, length=4): четыре символа описываются одним триплетом. Для более длинных текстов с большим числом повторов (исходный код, логи) эффект сжатия LZ77 заметно возрастает.

4. Варианты LZ77 и современная эволюция

После предложения LZ77 в 1977 году появилось множество вариантов, каждый из которых оптимизировал определённый аспект для конкретного сценария. В таблице ниже сравниваются основные члены семейства LZ77.

АлгоритмКлючевое улучшениеСтепень сжатияСкорость сжатияСкорость распаковкиТипичное применение
LZ77 (оригинал)Триплетное кодированиеНизкаяМедленноСреднеОбучение
LZSSФлаги для разделения совпадений/литераловСредняяСреднеБыстроРанние системы
DEFLATELZSS + Huffman в два проходаВыше среднегоСреднеБыстроZIP/GZIP/PNG
LZMAБольшое окно + range coding + оптимальный разборВысокаяМедленноСредне7z/xz архивы
LZ4Жертвует степенью ради скоростиНизкаяОчень быстроОчень быстро (4 ГБ/с)Реальное время / ядро
LZWЯвный словарь (без скользящего окна)СредняяБыстроБыстроGIF/TIFF
ZSTDВариант LZ77 + FSE + словариВысокаяБыстроОчень быстроСовременное общее

С точки зрения тенденций эволюции, современные алгоритмы (ZSTD, brotli) значительно повысили скорость при сохранении высокой степени сжатия, постепенно заменяя DEFLATE как новый стандарт. Но основная идея LZ77 — словарные ссылки со скользящим окном — остаётся неизменной, все варианты строятся на этой основе.

СценарийРекомендуемый алгоритмОбоснованиеТиповая степень сжатия
Архивация файловLZMA (xz)Максимальная степень, скорость не важна70–85%
Общее сжатиеZSTDБаланс степени и скорости60–80%
Передача в реальном времениLZ4Распаковка 4 ГБ/с, минимальная задержка50–65%
Web-передачаDEFLATE/GZIPЛучшая совместимость, поддержка всеми браузерами50–70%
Графические форматыDEFLATE (PNG)Сжатие без потерь, подходит для графики50–75%
Данные в памятиLZ4Низкая нагрузка на CPU, подходит для частого сжатия50–65%

О конкретном применении DEFLATE в формате PNG можно прочитать в Подробное объяснение принципа сжатия PNG. О разнице между сжатием без потерь и сжатием с потерями можно прочитать в Сжатие без потерь vs сжатие с потерями: ключевые различия.

5. Часто задаваемые вопросы FAQ

Q1: Что такое алгоритм LZ77?

LZ77 — это алгоритм словарного сжатия на основе скользящего окна, предложенный Лемпелом и Зивом в 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 + Хаффман, средняя степень сжатия и скорость; LZ4 жертвует степенью сжатия ради максимальной скорости, самая низкая степень сжатия, но скорость распаковки до 4GB/s. Выбор зависит от сценария: для архивации — LZMA, для общего использования — DEFLATE/ZSTD, для реального времени — LZ4.

Заключение

LZ77 — это родоначальник алгоритмов словарного сжатия, основной принцип — "скользящее окно + триплетные ссылки": использовать исторические данные как неявный словарь, при обнаружении повторяющегося содержимого выводить триплет (distance, length, next_char). Чистый LZ77 может приводить к увеличению размера для коротких текстов, но в комбинации с кодированием Хаффмана (DEFLATE) становится стандартным решением для сжатия ZIP/GZIP/PNG. Современные варианты LZMA преследуют максимальную степень сжатия, LZ4 — максимальную скорость, ZSTD — баланс обоих.

Ключевые три момента для понимания LZ77: первое — скользящее окно определяет диапазон совпадений (DEFLATE 32KB, LZMA 8MB), второе — триплет является базовой единицей кодирования (обратный ход + длина + следующий символ), третье — стратегия поиска совпадений определяет производительность (хеш-цепочки самые быстрые, суффиксные деревья самые оптимальные). Гибридное кодирование LZ77 + Хаффман — золотой стандарт современного сжатия без потерь.

Нужно сжать файлы? Попробуйте SmartSlim

Основан на собственном движке сжатия Rust, поддерживает 10 основных категорий и более 40 форматов, включая PDF/изображения/видео/Office/OFD, локальное сжатие без передачи данных.