Лисья Нора

Оглавление


§ Задача сжатия

В это статье речь пойдет об LZ-подобных алгоритмах сжатия без потерь. Но для начала я расскажу что из себя представляет задача сжатия. Исходная задача в том, чтобы уменьшить размер данных. Это можно сделать двумя способами – с потерями и без потерь. Первый способ рассматриваться не будет – он относится к алгоритмам сжатия аудио и видео информации. Второй более интересный. Основная суть, идея и задача любого алгоритма сжатия без потерь в том, чтобы найти повторяющиеся тем или иным образом участки в данных и создать их более короткое представление.

§ Алгоритм RLE

Существует один из простейших алгоритмов сжатия – оно называется RLE. Работает оно очень просто. Входящая строка разбивается на фрагменты одинаковых, идущих один за другим байтов и пишется сначала их количество, а потом сам повторяющийся фрагмент.
Рассмотрим фрагмент AAAAAAAAAAABBBBBBB. Здесь видно, что сначала идут одиннадцать букв A, а потом идут 7 букв B. Если это переписать в виде RLE-кодирования, то тогда будет выглядеть так 11A7B. Очевидно, что такая запись более короткая по сравнению с входящими данными. Но этот алгоритм совершенно неэффективен, если таких повторов немного. Существуют разные модификации метода сжатия RLE, но так или иначе, он неэффективен на обычных данных.

§ Метод скользящего окна

Он заключается в том, чтобы находить совпадения текста, которые отстоят на определенном расстоянии до текущего символа. Объясню сразу на примере. Есть строка A FOX HAS FOX TAIL. Как можно заметить, тут есть одинаковые подстроки " FOX " (включая пробел).
A FOX HAS FOX TAIL
^^^^^ ^^^^^
Другими словами, тут есть возможность сжать текст. В алгоритмах сжатия со скользящим окном сжатие происходит следующим образом: сначала в поток записываются символы, для которых невозможно найти предыдущие совпадения.
Итак, начнем разбор:
"A" - ранее в словаре ничего не было, добавляем ее просто в вывод
" " - ранее не было, в вывод
"F" - аналогично
"O" - пропуск
"X" - пропуск
" " - было ранее, надо отступить назад на 4 символа и взять 1, но это неэффективно, пропуск
"H" - пропуск
"A" - было 7 символов назад, но 1 символ лишь, пропуск
"S" - пропуск
" FOX " - а вот тут как раз и найдено, 8 символов назад, 5 символов длина
Поскольку найдено совпадение более чем 2 символа, то это значит, что можно вместо " FOX " просто вставить ссылку, которая будет указывать на то, что 8 символов назад длиной 5 символов есть слово " FOX ". И поскольку это так, то начинается побайтовое копирование из ранее встреченного места.
Таким образом, получается сжатие за счет вставки более короткой ссылки по сравнению с теми данными, которые будут сжаты этой ссылкой.

§ Особенности метода сжатия

Компрессия методом скользящего окна может предусмотреть копирование и 20 символов, начиная с позиции всего лишь 1 символ назад. Представим ситуацию, когда получена такая строка:
"ABABABABABABABAB"
Казалось бы, как тут закодировать оптимально? Все очень просто. Сначала выдаем 2 символа "AB", после чего ставим ссылку на 2 символа назад и копируем 14 символов!
Разберем по шагам:
1. "A" пишем в поток
2. "B" пишем в поток
3. --> А тут находится ссылка -2 символа назад и 14 символов длиной. Там буква "A"
Пишем в поток, получаем "ABA"
4. Сдвигаемся +1 вперед, пишем "B", получаем "ABAB"
5. Сдвигаемся +1 вперед, а там уже записана "A", копируем ее, получаем "ABABA"
6. Сдвигаемся +1 вперед, а там уже записана "B", копируем ее, получаем "ABABAB"
7. И так далее
В итоге получается исходная строка. Элегантно!

§ Блоки

Обычно есть 2 типа блоков при компрессии, блок 0 – это несжатые данные, и блок 1 – ссылка на данные и ее длина
Например, если идет блок несжатых данных, то указывается бит 0, и далее длина, которая обычно не превышает некоторого значения. Потом обязательно идет ссылка, после нее тоже может идти ссылка и так далее. Это определяется типом блока.
Приведу пример.
Допустим, закодировали строку A FOX HAS FOX TAIL. Первые 9 символов – это несжатые данные:
Т L Строка
0 9 A FOX HAS
1 8 5
0 4 TAIL
Таким образом, декомпрессия прошла успешно.