Алгоритмы LZ77 и LZ78 — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
м
Строка 3: Строка 3:
  
 
== LZ77 ==
 
== LZ77 ==
Можно сказать, что алгоритмы семейства LZ* представляют собой более сложное обобщение простого и интуитивно понятного способа сжатия данных, используемого в [[RLE]].
+
=== Описание алгоритма ===
=== Принципы работы алгоритма ===
+
LZ77 использует уже просмотренную часть сообщения как словарь. Чтобы достигнуть сжатия, алгоритм пытается заменить очередной фрагмент сообщения на указатель в содержимое словаря.
Основная идея алгоритма <tex>-</tex> это замена повторного вхождения строки ссылкой на одну из предыдущих позиций вхождения.
+
 
Для этого используют метод скользящего окна.
+
В качестве модели данных LZ77 использует "скользящее" по сообщению окно, разделенное на две неравных части. Первая часть, большая по размеру, включает уже просмотренную часть сообщения. Вторая, намного меньшая, - буфер, содержащий еще не закодированные символы. Как правило, размер окна - несколько килобайтов. Буфер намного меньше, обычно не больше, чем сто байтов. Алгоритм пытается найти фрагмент в словаре, который совпадает с содержанием буфера.
Скользящее окно можно представить в виде динамической структуры данных, которая организована так, чтобы запоминать «сказанную» ранее информацию и предоставлять к ней доступ.
+
 
Таким образом, сам процесс сжимающего кодирования согласно LZ77 напоминает написание программы, команды которой позволяют обращаться к элементам скользящего окна, и вместо значений сжимаемой последовательности вставлять ссылки на эти значения в скользящем окне.
+
Алгоритм LZ77 выдает коды, состоящие из трех элементов:
В стандартном алгоритме LZ77 совпадения строки кодируются парой:
+
 
* длина совпадения (match length)
+
*смещение в словаре относительно его начала подстроки, которая соответствует содержанию буфера;
* смещение (offset) или дистанция (distance)
+
*длина подстроки;
Кодируемая пара трактуется именно как команда копирования символов из скользящего окна с определенной позиции, или дословно как: «Вернуться в словаре на ''значение смещения''  символов и скопировать ''значение длины'' символов, начиная с текущей позиции».
+
*первый символ в буфере после подстроки.
Особенность данного алгоритма сжатия заключается в том, что использование кодируемой пары ''длина-смещение'' является не только приемлемым, но и эффективным в тех случаях, когда значение длины превышает значение смещения.
+
 
Пример с командой копирования не совсем очевиден: «Вернуться на 1 символ назад в буфере и скопировать 7 символов, начиная с текущей позиции». Каким образом можно скопировать 7 символов из буфера, когда в настоящий момент в буфере находится только 1 символ? Однако следующая интерпретация кодирующей пары может прояснить ситуацию: каждые 7 последующих символов совпадают (эквивалентны) с 1 символом перед ними.
+
После этого алгоритм перемещает окно на длину совпадающей подстроки +1 символ влево.
Это означает, что каждый символ можно однозначно определить переместившись назад в буфере, даже если данный символ еще отсутствует в буфере на момент декодирования текущей пары ''длина-смещение''.
+
 
=== Описания алгоритма===
+
Если совпадение не найдено, алгоритм выдает код ''<0, 0, первый символ в буфере>'' и продолжает свою работу. Хотя такое решение неэффективно, оно гарантирует, что алгоритм сможет закодировать любое сообщение.
LZ77 использует скользящее по сообщению окно. Допустим, на текущей итерации окно зафиксировано. С правой стороны окна наращиваем подстроку, пока она есть в строке <скользящее окно + наращиваемая строка> и начинается в скользящем окне. Назовем наращиваемую строку буфером. После наращивания алгоритм выдает код состоящий из трех элементов:
+
=== Пример ===
* смещение в окне;
 
* длина буфера;
 
* последний символ буфера.
 
В конце итерации алгоритм сдвигает окно на длину равную длине буфера+1.
 
=== Пример <tex>kabababababz</tex>  ===
 
 
{| border="1"  
 
{| border="1"  
  !Содержимое окна
+
  !Сообщение
  !Содержимое буфера
+
  !Подстрока
  !КОД
+
  !Код
 
  |-
 
  |-
  |<tex>kabababababz</tex>
+
  |<tex>\fbox{kababa}bababz</tex>
  |<tex>k</tex>
+
  |
 
  |<0,0,<tex>k</tex>>
 
  |<0,0,<tex>k</tex>>
 
  |-
 
  |-
  |<tex>kabababababz</tex>
+
  |<tex>k\fbox{ababab}ababz</tex>
  |<tex>a</tex>
+
  |
 
  |<0,0,<tex>a</tex>>
 
  |<0,0,<tex>a</tex>>
 
  |-
 
  |-
  |<tex>kabababababz</tex>
+
  |<tex>ka\fbox{bababa}babz</tex>
  |<tex>b</tex>
+
  |
 
  |<0,0,<tex>b</tex>>
 
  |<0,0,<tex>b</tex>>
 
  |-
 
  |-
  |<tex>k\fbox{ab}ababababz</tex>
+
  |<tex>kab\fbox{ababab}abz</tex>
  |<tex>aba</tex>
+
  |<tex>ab</tex>
 
  |<2,2,<tex>a</tex>>
 
  |<2,2,<tex>a</tex>>
 
  |-
 
  |-
  |<tex>kaba\fbox{babab}abz</tex>
+
  |<tex>kababa\fbox{bababz}</tex>
  |<tex>bababz</tex>
+
  |<tex>babab</tex>
 
  |<2,5,<tex>z</tex>>
 
  |<2,5,<tex>z</tex>>
 
  |}
 
  |}

Версия 19:42, 10 апреля 2012

LZ77 и LZ78 - алгоритмы сжатия без потерь, опубликованные в статьях Абрахама Лемпеля и Якоба Зива в 1977 и 1978 годах. Эти алгоритмы - самые известные варианты в семье LZ*, которая также включает LZW, LZSS, LZMA и другие алгоритмы. Оба алгоритма - алгоритмы со словарным подходом. Алгоритм LZ77 использует "скользящее окно", которое эквивалентно неявному использованию словарного подхода, сначала предложенного в LZ78.

LZ77

Описание алгоритма

LZ77 использует уже просмотренную часть сообщения как словарь. Чтобы достигнуть сжатия, алгоритм пытается заменить очередной фрагмент сообщения на указатель в содержимое словаря.

В качестве модели данных LZ77 использует "скользящее" по сообщению окно, разделенное на две неравных части. Первая часть, большая по размеру, включает уже просмотренную часть сообщения. Вторая, намного меньшая, - буфер, содержащий еще не закодированные символы. Как правило, размер окна - несколько килобайтов. Буфер намного меньше, обычно не больше, чем сто байтов. Алгоритм пытается найти фрагмент в словаре, который совпадает с содержанием буфера.

Алгоритм LZ77 выдает коды, состоящие из трех элементов:

  • смещение в словаре относительно его начала подстроки, которая соответствует содержанию буфера;
  • длина подстроки;
  • первый символ в буфере после подстроки.

После этого алгоритм перемещает окно на длину совпадающей подстроки +1 символ влево.

Если совпадение не найдено, алгоритм выдает код <0, 0, первый символ в буфере> и продолжает свою работу. Хотя такое решение неэффективно, оно гарантирует, что алгоритм сможет закодировать любое сообщение.

Пример

Сообщение Подстрока Код
[math]\fbox{kababa}bababz[/math] <0,0,[math]k[/math]>
[math]k\fbox{ababab}ababz[/math] <0,0,[math]a[/math]>
[math]ka\fbox{bababa}babz[/math] <0,0,[math]b[/math]>
[math]kab\fbox{ababab}abz[/math] [math]ab[/math] <2,2,[math]a[/math]>
[math]kababa\fbox{bababz}[/math] [math]babab[/math] <2,5,[math]z[/math]>

LZ78

Описание алгоритма

В отличие от LZ77, работающего с уже полученными данными, LZ78 ориентируется на данные, которые только будут получены (LZ78 не использует скользящее окно, он хранит словарь из уже просмотренных фраз). Алгоритм считывает символы сообщения до тех пор, пока накапливаемая подстрока входит целиком в одну из фраз словаря. Как только эта строка перестанет соответствовать хотя бы одной фразе словаря, алгоритм генерирует код, состоящий из индекса строки в словаре, которая до последнего введенного символа содержала входную строку, и символа, нарушившего совпадение. Затем в словарь добавляется введенная подстрока. Если словарь уже заполнен, то из него предварительно удаляют менее всех используемую в сравнениях фразу. Если в конце алгоритма мы не находим символ, нарушивший совпадения, то тогда мы выдаем код в виде <индекс строки в словаре без последнего символа, последний символ>.

Пример [math]kabababababz[/math]

Содержимое словаря Содержимое считываемой строки КОД
[math]k[/math] <0,[math]k[/math]>
[math]k[/math] [math]a[/math] <0,[math]a[/math]>
[math]k[/math], [math]a[/math] [math]b[/math] <0,[math]b[/math]>
[math]k[/math], [math]\fbox{a}[/math], [math]b[/math] [math]ab[/math] <2,[math]b[/math]>
[math]k[/math], [math]a[/math], [math]b[/math], [math]\fbox{ab}[/math] [math]aba[/math] <4,[math]a[/math]>
[math]k[/math], [math]a[/math], [math]\fbox{b}[/math], [math]ab[/math], [math]aba[/math] [math]ba[/math] <3,[math]a[/math]>
[math]k[/math], [math]a[/math], [math]b[/math], [math]ab[/math], [math]\fbox{aba}[/math], [math]ba[/math] [math]abab[/math] <5,[math]b[/math]>
[math]k[/math], [math]a[/math], [math]b[/math], [math]ab[/math], [math]aba[/math], [math]ba[/math], [math]abab[/math] [math]z[/math] <0,[math]z[/math]>

Ссылки