Алгоритм LZW — различия между версиями
Shersh (обсуждение | вклад) |
|||
Строка 11: | Строка 11: | ||
Процесс сжатия выглядит следующим образом: последовательно считываются символы входного потока и происходит проверка, существует ли в созданной таблице строк такая строка. Если такая строка существует, считывается следующий символ, а если строка не существует, в поток заносится код для предыдущей найденной строки, строка заносится в таблицу, а поиск начинается снова. | Процесс сжатия выглядит следующим образом: последовательно считываются символы входного потока и происходит проверка, существует ли в созданной таблице строк такая строка. Если такая строка существует, считывается следующий символ, а если строка не существует, в поток заносится код для предыдущей найденной строки, строка заносится в таблицу, а поиск начинается снова. | ||
− | Например, если сжимают байтовые данные (текст), то строк в таблице окажется 256(от "0" до "255"). Если используется 10-битный код, то под коды для строк остаются значения в диапазоне от 256 до 1023. Новые строки формируют таблицу последовательно, т. е. можно считать индекс строки ее кодом. | + | Например, если сжимают байтовые данные (текст), то строк в таблице окажется <tex>256</tex> (от <tex>"0"</tex> до <tex>"255"</tex>). Если используется <tex>10</tex>-битный код, то под коды для строк остаются значения в диапазоне от <tex>256</tex> до <tex>1023/<tex>. Новые строки формируют таблицу последовательно, т. е. можно считать индекс строки ее кодом. |
Для декодирования на вход подается только закодированный текст, поскольку алгоритм LZW может воссоздать соответствующую таблицу преобразования непосредственно по закодированному тексту. | Для декодирования на вход подается только закодированный текст, поскольку алгоритм LZW может воссоздать соответствующую таблицу преобразования непосредственно по закодированному тексту. | ||
Строка 40: | Строка 40: | ||
Рассмотрим пример сжатия и декодирования сообщения. | Рассмотрим пример сжатия и декодирования сообщения. | ||
− | Сначала создадим начальный словарь единичных символов. В стандартной кодировке ASCII имеется 256 различных символов, поэтому, для того, чтобы все они были корректно закодированы (если нам неизвестно, какие символы будут присутствовать в исходном файле, а какие - нет), начальный размер кода будет равен 8 битам. Если нам заранее известно, что в исходном файле будет меньшее количество различных символов, то вполне разумно уменьшить количество бит. Чтобы инициализировать таблицу, мы установим соответствие кода 0 соответствующему символу с битовым кодом <tex>00000000</tex>, тогда 1 | + | Сначала создадим начальный словарь единичных символов. В стандартной кодировке ASCII имеется <tex>256</tex> различных символов, поэтому, для того, чтобы все они были корректно закодированы (если нам неизвестно, какие символы будут присутствовать в исходном файле, а какие - нет), начальный размер кода будет равен 8 битам. Если нам заранее известно, что в исходном файле будет меньшее количество различных символов, то вполне разумно уменьшить количество бит. Чтобы инициализировать таблицу, мы установим соответствие кода 0 соответствующему символу с битовым кодом <tex>00000000</tex>, тогда <tex>1</tex> |
− | соответствует символу с кодом <tex>00000001</tex>, и т.д., до кода 255. На самом деле мы указали, что каждый код от 0 до 255 является корневым. | + | соответствует символу с кодом <tex>00000001</tex>, и т.д., до кода <tex>255</tex>. На самом деле мы указали, что каждый код от <tex>0</tex> до <tex>255</tex> является корневым. |
{| class="wikitable" border = 1, style="float:right; text-align: right; margin-left: auto; margin-right: auto;" | {| class="wikitable" border = 1, style="float:right; text-align: right; margin-left: auto; margin-right: auto;" | ||
Строка 59: | Строка 59: | ||
Больше в таблице не будет других кодов, обладающих этим свойством.<br> | Больше в таблице не будет других кодов, обладающих этим свойством.<br> | ||
− | По мере роста словаря, размер групп должен расти, с тем, чтобы учесть новые элементы. 8-битные группы дают 256 возможных комбинации бит, поэтому, когда в словаре появится 256-е слово, алгоритм должен перейти к 9-битным группам. При появлении 512-ого слова произойдет переход к 10-битным группам, что дает возможность запоминать уже 1024 слова и т.д. | + | По мере роста словаря, размер групп должен расти, с тем, чтобы учесть новые элементы. <tex>8</tex>-битные группы дают <tex>256</tex> возможных комбинации бит, поэтому, когда в словаре появится <tex>256</tex>-е слово, алгоритм должен перейти к <tex>9</tex>-битным группам. При появлении <tex>512</tex>-ого слова произойдет переход к <tex>10</tex>-битным группам, что дает возможность запоминать уже <tex>1024</tex> слова и т.д. |
− | В нашем примере алгоритму заранее известно о том, что будет использоваться всего 5 различных символов, следовательно, для их хранения будет использоваться минимальное количество бит, позволяющее нам их запомнить, то есть 3 ( 8 различных комбинаций ). | + | В нашем примере алгоритму заранее известно о том, что будет использоваться всего <tex>5</tex> различных символов, следовательно, для их хранения будет использоваться минимальное количество бит, позволяющее нам их запомнить, то есть <tex>3</tex> (<tex>8</tex> различных комбинаций). |
=== Кодирование === | === Кодирование === | ||
Строка 207: | Строка 207: | ||
Итак, мы получаем закодированное сообщение <tex>0 1 0 2 5 0 3 9 8 6 4</tex>. | Итак, мы получаем закодированное сообщение <tex>0 1 0 2 5 0 3 9 8 6 4</tex>. | ||
− | Каждый символ исходного сообщения был закодирован группой из трех бит, сообщение содержало 16 символов, следовательно длина сообщения составляла 3 * 16 = 48 бит. | + | Каждый символ исходного сообщения был закодирован группой из трех бит, сообщение содержало 16 символов, следовательно длина сообщения составляла <tex>3 * 16 = 48</tex> бит. |
− | Закодированное же сообщение так же сначала кодировалось трехбитными группами, а про появлении в словаре восьмого слова - четырехбитными, итого длина сообщения составила 7 * 3 + 4 * 4 = 37 бит, что на 11 бит короче исходного. | + | Закодированное же сообщение так же сначала кодировалось трехбитными группами, а про появлении в словаре восьмого слова - четырехбитными, итого длина сообщения составила <tex>7 * 3 + 4 * 4 = 37</tex> бит, что на <tex>11</tex> бит короче исходного. |
=== Декодирование === | === Декодирование === | ||
Строка 215: | Строка 215: | ||
Особенность LZW заключается в том, что для декомпрессии нам не надо сохранять таблицу строк в файл для распаковки. Алгоритм построен таким образом, что мы в состоянии восстановить таблицу строк, пользуясь только потоком кодов. | Особенность LZW заключается в том, что для декомпрессии нам не надо сохранять таблицу строк в файл для распаковки. Алгоритм построен таким образом, что мы в состоянии восстановить таблицу строк, пользуясь только потоком кодов. | ||
− | Теперь представим ,что мы получили закодированное сообщение, приведённое выше, и нам нужно его декодировать. Прежде всего, нам нужно знать начальный словарь, а последующие записи словаря мы можем реконструировать уже на ходу, поскольку они являются просто конкатенацией предыдущих записей. | + | Теперь представим, что мы получили закодированное сообщение, приведённое выше, и нам нужно его декодировать. Прежде всего, нам нужно знать начальный словарь, а последующие записи словаря мы можем реконструировать уже на ходу, поскольку они являются просто конкатенацией предыдущих записей. |
Версия 19:22, 13 ноября 2014
Непосредственным предшественником LZW является алгоритм LZ78, опубликованный Абрахамом Лемпелем (Abraham Lempel) и Якобом Зивом (Jacob Ziv) в 1978 г. Этот алгоритм воспринимался как математическая абстракция до 1984 г., когда Терри Уэлч (Terry A. Welch) опубликовал свою работу с модифицированным алгоритмом, получившим в дальнейшем название LZW (Lempel—Ziv—Welch).
Содержание
Применение
Опубликование алгоритма LZW произвело большое впечатление на всех специалистов по сжатию информации. За этим последовало большое количество программ и приложений с различными вариантами этого метода.
Этот метод позволяет достичь одну из наилучших степеней сжатия среди других существующих методов сжатия графических данных, при полном отсутствии потерь или искажений в исходных файлах. В настоящее время испольуется в файлах формата TIFF, PDF, GIF, PostScript и других, а также отчасти во многих популярных программах сжатия данных (ZIP, ARJ, LHA).
Описание
Процесс сжатия выглядит следующим образом: последовательно считываются символы входного потока и происходит проверка, существует ли в созданной таблице строк такая строка. Если такая строка существует, считывается следующий символ, а если строка не существует, в поток заносится код для предыдущей найденной строки, строка заносится в таблицу, а поиск начинается снова.
Например, если сжимают байтовые данные (текст), то строк в таблице окажется
(от до ). Если используется -битный код, то под коды для строк остаются значения в диапазоне от до заносится первый символ сообщения.- Шаг 2. Считать очередной символ из сообщения.
- Шаг 3. Если
- Если фраза уже имеется в словаре, то присвоить входной фразе значение и перейти к Шагу 2,
- Иначе выдать код для входной фразы , добавить в словарь и присвоить входной фразе значение . Перейти к Шагу 2.
— это символ конца сообщения, то выдать код для , иначе:
- Конец.
Декодирование
- Начало.
- Шаг 1. Все возможные символы заносятся в словарь. Во входную фразу заносится первый код декодируемого сообщения.
- Шаг 2. Считать очередной код из сообщения.
- Шаг 3. Если
- Если фразы под кодом нет в словаре, вывести фразу, соответствующую коду , а фразу с кодом занести в словарь.
- Иначе присвоить входной фразе код и перейти к Шагу 2.
— это конец сообщения, то выдать символ, соответствующий коду , иначе:
- Конец.
Пример
Рассмотрим пример сжатия и декодирования сообщения. Сначала создадим начальный словарь единичных символов. В стандартной кодировке ASCII имеется
различных символов, поэтому, для того, чтобы все они были корректно закодированы (если нам неизвестно, какие символы будут присутствовать в исходном файле, а какие - нет), начальный размер кода будет равен 8 битам. Если нам заранее известно, что в исходном файле будет меньшее количество различных символов, то вполне разумно уменьшить количество бит. Чтобы инициализировать таблицу, мы установим соответствие кода 0 соответствующему символу с битовым кодом , тогда соответствует символу с кодом , и т.д., до кода . На самом деле мы указали, что каждый код от до является корневым.Символ | Битовый код |
---|---|
a | 000 |
b | 001 |
c | 010 |
d | 011 |
e | 100 |
Больше в таблице не будет других кодов, обладающих этим свойством.
По мере роста словаря, размер групп должен расти, с тем, чтобы учесть новые элементы. -битные группы дают возможных комбинации бит, поэтому, когда в словаре появится -е слово, алгоритм должен перейти к -битным группам. При появлении -ого слова произойдет переход к -битным группам, что дает возможность запоминать уже слова и т.д.
В нашем примере алгоритму заранее известно о том, что будет использоваться всего
различных символов, следовательно, для их хранения будет использоваться минимальное количество бит, позволяющее нам их запомнить, то есть ( различных комбинаций).Кодирование
Пусть мы сжимаем последовательность
.- Шаг 1: Тогда, согласно изложенному выше алгоритму, мы добавим к изначально пустой строке и проверим, есть ли строка в таблице. Поскольку мы при инициализации занесли в таблицу все строки из одного символа, то строка есть в таблице.
- Шаг 2: Далее мы читаем следующий символ из входного потока и проверяем, есть ли строка в таблице. Такой строки в таблице пока нет.
Добавляем в таблицу
. В поток: ;- Шаг 3: — нет. В таблицу: . В поток: ;
- Шаг 4: — нет. В таблицу: . В поток: ;
- Шаг 5: — нет. В таблицу: . В поток: ;
- Шаг 6: — есть в таблице; — нет. В таблицу: . В поток: ;
- Шаг 7: — нет. В таблицу: . В поток: ;
- Шаг 8: — нет. В таблицу: . В поток: ;
- Шаг 9: — есть в таблице; — нет. В таблицу: . В поток: ;
- Шаг 10: — есть в таблице; — нет. В таблицу: . В поток: ;
- Шаг 11: — есть в таблице; — нет. В таблицу: . В поток: ;
- Шаг 12: И, наконец последняя строка , за ней идет конец сообщения, поэтому мы просто выводим в поток .
Текущая строка | Текущий символ | Следующий символ | Вывод | Словарь | ||
---|---|---|---|---|---|---|
Код | Биты | |||||
ab | a | b | 0 | 000 | 5: | ab |
ba | b | a | 1 | 001 | 6: | ba |
ac | a | c | 0 | 000 | 7: | ac |
ca | c | a | 2 | 010 | 8: | ca |
ab | a | b | - | - | - | - |
aba | b | a | 5 | 101 | 9: | aba |
ad | a | d | 0 | 000 | 10: | ad |
da | d | a | 3 | 011 | 11: | da |
ab | a | b | - | - | - | - |
aba | b | a | - | - | - | - |
abac | a | c | 9 | 1001 | 12: | abac |
ca | c | a | - | - | - | - |
cab | a | b | 8 | 1000 | 13: | cab |
ba | b | a | - | - | - | - |
bae | a | e | 6 | 0110 | 14: | bae |
e | e | - | 4 | 0100 | - | - |
Итак, мы получаем закодированное сообщение
.Каждый символ исходного сообщения был закодирован группой из трех бит, сообщение содержало 16 символов, следовательно длина сообщения составляла
бит.Закодированное же сообщение так же сначала кодировалось трехбитными группами, а про появлении в словаре восьмого слова - четырехбитными, итого длина сообщения составила
бит, что на бит короче исходного.Декодирование
Особенность LZW заключается в том, что для декомпрессии нам не надо сохранять таблицу строк в файл для распаковки. Алгоритм построен таким образом, что мы в состоянии восстановить таблицу строк, пользуясь только потоком кодов.
Теперь представим, что мы получили закодированное сообщение, приведённое выше, и нам нужно его декодировать. Прежде всего, нам нужно знать начальный словарь, а последующие записи словаря мы можем реконструировать уже на ходу, поскольку они являются просто конкатенацией предыдущих записей.
Данные | На выходе | Новая запись | ||||
---|---|---|---|---|---|---|
Биты | Код | Полная | Частичная | |||
000 | 0 | a | - | - | 5: | a? |
001 | 1 | b | 5: | ab | 6: | b? |
000 | 0 | a | 6: | ba | 7: | a? |
010 | 2 | c | 7: | ac | 8: | c? |
101 | 5 | ab | 8: | ca | 9: | ab? |
000 | 0 | a | 9: | aba | 10: | a? |
011 | 3 | d | 10: | ad | 11: | d? |
1001 | 9 | aba | 11: | da | 12: | aba? |
1000 | 8 | ca | 12: | abac | 13: | ca? |
0110 | 6 | ba | 13: | cab | 14: | ba? |
0100 | 4 | e | 14: | bae | - | - |
Примечание
Для повышения степени сжатия изображений данным методом часто используется одна «хитрость» реализации этого алгоритма. Некоторые файлы, подвергаемые сжатию с помощью LZW, имеют часто встречающиеся цепочки одинаковых символов, например
… или … и т. п. Их непосредственное сжатие будет генерировать выходной код и т.д. Спрашивается, можно ли в этом частном случае повысить степень сжатия?Оказывается, это возможно, если оговорить некоторые действия:
Мы знаем, что для каждого кода надо добавлять в таблицу строку, состоящую из уже присутствующей там строки и символа, с которого начинается следующая строка в потоке.
- Итак, кодировщик заносит первую в строку, ищет и находит в словаре. Добавляет в строку следующую , находит, что нет в словаре. Тогда он добавляет запись : в словарь и выводит метку ( ) в выходной поток.
- Далее строка инициализируется второй , то есть принимает вид вводится третья , строка вновь равна , которая теперь имеется в словаре.
- Если появляется четвертая , то строка равна , которой нет в словаре. Словарь пополняется этой строкой, а на выход идет метка ( ).
- После этого строка инициализируется третьей , и т.д. и т.п. Дальнейший процесс вполне ясен.
Текущая строка | Текущий символ | Следующий символ | Вывод | Словарь | ||
---|---|---|---|---|---|---|
Код | Биты | |||||
aa | a | a | 0 | 000 | 5: | aa |
aa | a | a | - | - | - | - |
aaa | a | a | 5 | 101 | 6: | aaa |
a | a | a | - | - | - | - |
aa | a | a | - | - | - | - |
aaa | a | - | 6 | 110 | - | - |
В результате на выходе получаем последовательность
..., которая короче прямого кодирования стандартным методом LZW.Можно показать, что такая последовательность будет корректно восстановлена. Декодировщик сначала читает первый код – это
, которому соответствует символ . Затем читает код , но этого кода в его таблице нет. Но мы уже знаем, что такая ситуация возможна только в том случае, когда добавляемый символ равен первому символу только что считанной последовательности, то есть . Поэтому он добавит в свою таблицу строку с кодом , а в выходной поток поместит . И так может быть раскодирована вся цепочка кодов.Мало того, описанное выше правило кодирования мы можем применять в общем случае не только к подряд идущим одинаковым символам, но и к последовательностям, у которых очередной добавляемый символ равен первому символу цепочки.
Преимущества алгоритма LZW
- Алгоритм является однопроходным.
- Для декомпрессии не надо сохранять таблицу строк в файл для распаковки. Алгоритм построен таким образом, что мы в состоянии восстановить таблицу строк, пользуясь только потоком кодов.
Недостатки алгоритма LZW
- Алгоритм не проводит анализ входных данных.