Алгоритм сжатия LZ78, особенности функционирования

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

Каждая метка соответствует последовательности во входном файле, и эта последовательность добавляется в словарь после того, как метка записана в выходной сжатый файл. Ничего из словаря не удаляется, что является одновременно и преимуществом над LZ77 (поскольку будущие строки могут совпадать даже с очень давними последовательностями) и недостатком (так как быстро растет объем словаря).

Словарь начинает строиться из пустой строки в позиции нуль. По мере поступления и кодирования символов, новые строки добавляются в позиции 1, 2 и т.д. Когда следующий символ х читается из входного файла, в словаре ищется строка из одного символа х. Если такой строки нет, то х добавляется в словарь, а на выход подается метка (0,0;). Эта метка означает строку «нуль x» (соединение нулевой строки и х). Если вхождение символа х обнаружено (скажем, в позиции 37), то читается следующий символ, и в словаре ищется вхождение двухсимвольной строки ху. Если такое не найдено, то в словарь записывается строка ху а на выход подается метка (37, у). Такая метка означает строку ху, так как позицию 37 в словаре занимает символ X. Процесс продолжается до конца входного файла.

В общем случае текущий символ читается и становится однобуквенной строкой. Затем кодер пытается найти ее в словаре. Если строка найдена, читается следующий символ и присоединяется к текущей строке, образуя двухбуквенную строку, которую кодер опять пытается найти в словаре. До тех пор пока такие строки находятся в словаре, происходит чтение новых символов и их присоединение к текущей строке. В некоторый момент такой строки в словаре не оказывается. Тогда кодер добавляет ее в словарь и строит метку, в первом поле которой стоит указатель на последнюю найденную в словаре строку, а во втором поле записан последний символ строки (на котором произошел обрыв успешных поисков).

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

Хорошей структурой для организации словаря является дерево, но не двоичное. Дерево начинается нулевой строкой в корне. Все строки, начинающиеся с нулевой строки (строки, для которых указатель в метке равен нулю), добавляются к дереву как потомки корня. В 8-битовом алфавите имеется всего 256 различных символов. В принципе, каждый узел дерева может иметь до 256 потомков. Следовательно, добавление новых узлов на дерево является динамическим процессом. Когда узел будет создаваться, у него еще нет потомков, поэтому необходимо зарезервировать некоторый объем памяти для них.

Поскольку удалять узлы с дерева не придется, не придется и заниматься перераспределением памяти, что несколько упрощает манипулирование с ней. На таком дереве очень легко искать строки и добавлять новые символы. Например, чтобы найти строку sil , программа ищет символ S в корне, затем его потомка i символа s, и так далее, спускаясь вниз по дереву.

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