Примеры словарного алгоритма сжатия LZ78

Когда символ s из si d появляется на входе при шаге 5, кодер находит узел «1-s» на дереве как потомка «null». Затем поступает символ i, но узел s не имеет такого потомка (у него в этот момент вовсе нет потомков). Тогда кодер добавляет узел «5-i» в виде потомка узла «1-s», что означает добавление на дерево строки si. Когда на входе появляется пробел между eastman и easil y на шаге 12, возникает похожая ситуация. Кодер обнаруживает узел «4-е», получает символ е, находит «7-е», получает а, но у «7-е» нет потомка а, поэтому он добавляет узел «12-а», что эквивалентно добавлению строки «еа».

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

Простейшее решение - это заморозить словарь, когда он переполнится. Новые узлы не добавляются, словарь становится статическим, но с его помощью можно по-прежнему кодировать последовательности. Удалить все дерево при переполнении и начать строить новое. Это решение эффективно разбивает данные на блоки, и в каждом блоке используется свой собственный словарь. Если содержимое сжимаемых данных меняется от блока к блоку, то этот метод дает хорошие результаты, поскольку в словаре не хранятся строки, которые с малой вероятностью поступят в дальнейшем. Здесь опять, как и в LZ77 неявно предполагается, что похожие данные будут группироваться близко друг к другу.

Утилита compress операционной системы UNIX использует более сложное решение. Эта программа (еще называемая LZC) использует алгоритм LZW с растущим словарем. Она начинает работать с маленьким словарем, состоящим всего из 2^9 = 512 строк, причем первые 256 уже заполнены. При использовании исходного словаря в сжатый файл записываются 9-битовые указатели. После заполнения этого словаря его размер удваивается до 1024 строк. С этого момента используются 10-битовые указатели. Этот процесс продолжается до тех пор, пока размер указателей не достигнет некоторого максимального значения, задаваемого пользователем (от 9 до 16 бит, причем 16 принято по умолчанию).

Когда наибольший допустимый словарь полностью заполняется, программа продолжает работать без изменения словаря (который теперь становится статическим), но одновременно делается мониторинг коэффициента сжатия. Если этот коэффициент превышает некоторый предустановленный порог, то происходит сброс словаря, процесс начинается с исходного 512-строчного словаря. При таком подходе словарь никогда не устаревает. Когда словарь заполнился, удалить из него некоторые самые старые строки, чтобы освободить место д,ля новых.

К сожалению, не существует хорошего алгоритма, который определял бы, какие строки удалять и в каком количестве. Декодер LZ78 работает примерно так же, как и кодер, строя словарь и оперируя с ним. Поэтому он более сложен, чем декодер LZ77. Эти слова! Как невинно и беспомощно они выглядят в словаре. Но сколько могущества для добра или для зла они проявляют в руках тех, кто умеет объединять их. — Натаниэль Хаусорн.

-----------------------------