Алгоритм RLE: описание, особенности, правила и примеры. Простейшие алгоритмы сжатия: RLE и LZ77


      1. Оформление документа

Скопируйте в свой каталог документ ТЕХ.doc и оформите его следующим образом:

и оформите этим стилем формулу, набранную в формате LaТ Е Х.


  1. Оформите заголовок «Литература» стилем «Заголовок 2 ». Информацию о книге Д. Кнута оформите в виде нумерованного списка.

  2. Найдите информацию о книге «Все про Т Е Х» на сайте издательства «Вильямс» и сделайте название книги гиперссылкой на найденную страницу. Проверьте работу гиперссылки.

      1. Алгоритм RLE


  1. Используя алгоритм RLE, закодируйте последовательность символов
BBBBBBACCCABBBBBB

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


  1. Раскодируйте последовательность, упакованную с помощью алгоритма RLE (приводятся шестнадцатеричные коды): 01 4D 8E 41 01 4D 8E 41 16 . Для определения символов по их шестнадцатеричным кодом используйте таблицу ASCII. Определите количество байтов в исходной и распакованной последовательности и вычислите коэффициент сжатия:

  2. Проверьте результат, полученный в предыдущем пункте, с помощью программы RLE. Предложите два способа проверки.

  3. Постройте последовательности, которые сжимаются алгоритмом RLE ровно в 2 раза, в 4 раза, в 5 раз. Проверьте свои ответы с помощью программы RLE.

    Несжатая последовательность

    Сжатая последовательность

    Коэффициент сжатия

    2

    4

    5

  4. Придумайте три последовательности, которые невозможно сжать с помощью алгоритма RLE:

    Несжатая последовательность

    «Сжатая» последовательность

    Коэффициент сжатия

  5. Используя программу RLE, примените RLE-сжатие к следующим файлам и найдите для каждого из них коэффициент сжатия:

    Файл

    Размер без сжатия

    Размер после сжатия

    Коэффициент сжатия

    grad_vert.bmp

    grad_horz.bmp

    grad_diag.jpg

  6. Объясните результаты, полученные в предыдущем пункте:

  • почему невыгодно сжимать рисунки в формате JPEG?

  • почему для двух рисунков в формате BMP одинакового размера коэффициенты сжатия по алгоритму RLE так сильно отличаются? Подсказка : откройте эти рисунки в любой программе просмотра.

  1. Оцените максимально достижимый коэффициент сжатия с помощью рассмотренного в учебнике варианта RLE-алгоритма. В каком случае его удастся достичь?
Ответ :

  1. Оцените коэффициент сжатия с помощью RLE-алгоритма в худшем случае. Опишите этот худший случай.
Ответ :

      1. Сравнение алгоритмов сжатия

При выполнении этой работы используются программы RLE (алгоритм сжатия RLE) и Huffman (кодирование Хаффмана и Шеннона-Фано).

  1. Запустите программу Huffman.exe и закодируйте строку «ЕНОТ НЕ ТОНЕТ», используя методы Шеннона-Фано и Хаффмана. Запишите результаты в таблицу:

Шеннон и Фано

Хаффман

Длина основного кода







Сделайте выводы.

Ответ :

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

Ответ :


  1. Повторите эксперимент с фразой «НОВОЕ ЕНОТОВО».

Шеннон и Фано

Хаффман

Длина основного кода

Длина кодовой таблицы (дерева)

Коэффициент сжатия (по основным кодам)

Коэффициент сжатия (с учетом дерева кодов)

Сделайте выводы.

Ответ :

Нарисуйте в тетради кодовые деревья, которые были построены программой при использовании обоих методов.


  1. Используя кнопку Анализ файла в программе Huffman a.txt 1 при побайтном кодировании.
Ответ :

  1. С помощью программ RLE и Huffman выполните сжатие файла a . txt разными способами. Запишите результаты в таблицу:

Объясните результат, полученный с помощью алгоритма RLE.

Ответ :


  1. Используя кнопку Анализ файла в программе Huffman , определите предельный теоретический коэффициент сжатия для файла a.txt.huf при побайтном кодировании. Объясните результат.
Ответ :

  1. Примените несколько раз повторное сжатие этого файла с помощью алгоритма Хаффмана (новые файлы получат имена a.txt.huf2 , a.txt.huf3 и т.д.) и заполните таблицу, каждый раз выполняя анализ полученного файла.

Размер файла



a.txt

a.txt.huf

a.txt.huf2

a.txt.huf3

a.txt.huf4

a.txt.huf5

Ответ :


  1. Выполните те же действия, используя метод Шеннона-Фано.

Размер файла

Предельный коэффициент сжатия

a.txt

a.txt.shf

a.txt.shf2

a.txt.shf3

a.txt.shf4

a.txt.shf5

Объясните, почему с некоторого момента при повторном сжатии файла его размер увеличивается.

Ответ :


  1. Сравните результаты сжатия этого файла с помощью алгоритма RLE, лучшие результаты, полученные методами Шеннона-Фано и Хаффмана, а также результат сжатия этого файла каким-нибудь архиватором.

Размер файла

Предельный коэффициент сжатия

RLE

Хаффман

Шеннон и Фано

ZIP

RAR

7Z

Объясните результаты и сделайте выводы.

Ответ :


      1. Использование архиватора


  1. Изучите возможности архиватора, который установлен на вашем компьютере (Ark , 7- Zip , WinRAR или др.).

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

  3. Распакуйте архив secret. zip , который упакован с паролем secretLatin . В подкаталогах, получившихся после распаковки, вы должны найти 3 файла, содержащие части высказывания на латинском языке, которое означает «договоры следует выполнять».

  4. Создайте новый текстовый файл latin.txt и запишите в него это высказывание на латыни. После этого удалите архив secret.zip .

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

Имя файла

Описание

Объем до

сжатия, Кб


Объем после сжатия, Кб

Коэффициент сжатия

random.dat

случайные данные

391

morning.zip

сжатый файл

244

sunset.jpg

рисунок в формате JPEG

730

prog.exe

программа для Windows

163

signal.mp3

звук в формате MP3

137

forest.wav

звук в формате WAV

609

ladoga.bmp

рисунок в формате BMP

9217

tolstoy.txt

текст

5379

Запишите в тетради выводы о том, какие файлы обычно сжимаются лучше, а какие – хуже.

  1. Если ваш архиватор позволяет создавать самораспаковывающиеся архивы, сравните размеры обычного архива и SFX-архива для файла tolstoy . txt :

Объясните, почему размеры двух архивов получились разные. После этого удалите оба созданных архива.

  1. Переместите рисунки в отдельный каталог Pictures , а звуковые файлы – в каталог Sounds.

  2. Упакуйте рисунки и звуки в архив Media с паролем media123 .

  3. Упакуйте все остальные файлы и папки в архив Data (без пароля).

  4. Удалите все файлы, кроме архивов Media и Data , и покажите работу учителю.

      1. Сжатие с потерями


  1. Скопируйте в свою папку файл valaam.jpg .

  2. Используя растровый графический редактор (GIMP , Photoshop ), сохраните несколько копий этого рисунка с разным качеством, от 0% до 100%.


Качество, %

0

10

20

30

40

50

60

70

80

90

100

Объем файла, Кбайт

С помощью табличного процессора постройте график по этим данным. Сделайте выводы.

  1. Просмотрите файлы, полученные при разных степенях сжатия. Выберите оптимальный на ваш взгляд вариант, когда при небольшом размере файла сохраняется приемлемое качество рисунка.

  2. Скопируйте в свою папку звуковой файл bears . mp 3 .

  3. Используя звуковой редактор (например, Audacity ), сохраните несколько копий этого звукового файла с разным качеством. Для формата Ogg Vorbis используйте качество от 0% до 100%, для формата MP3 – битрейт от 16 до 128 Кбит/с.

  4. В табличном процессоре заполните таблицу

Постройте график по этим данным. Объясните, почему получилась именно такая зависимость.

  1. Прослушайте файлы, полученные при разных степенях сжатия. Выберите оптимальный на ваш взгляд вариант, когда при небольшом размере файла сохраняется приемлемое качество звука.

Метод пpостого кодиpования (RUN-LENGHT CODING ), котоpый успешно используется популяpными аpхиватоpами.

Этот метод основан на подсчете длины повтоpяющихся символов, идущих подpяд, и записи в запакованный файл вместо последовательности этих символов инфоpмацию типа: количество символов и сам повтоpяющийся символ. Hапpимеp, имеется стpока типа "AAAAABBBCCCADDDEEL ". Она запакуется в последовательность типа "5A3B3CADDEEL ". Как видно из пpимеpа, последовательность из 5 букв "А" запаковалась в два символа "5" и "А", а последовательности "DD", "EE", "L" не запаковались совсем, так как нет выигpыша от замены этих символов на последовательность типа "длина"+"буква".

Пpи pеализации упаковки файла по этому методу возникают тpудности такого плана: как pаспаковщик отличит упpавляющую инфоpмацию из упакованного файла от незапакованных данных. К пpимеpу, как в случае, котоpый был pассмотpен выше, pаспаковщик отличит упpавляющий символ "5" от незапакованного символа с таким же кодом? Существует два ваpианта pешения данной пpоблемы:

(I) . Hайти символ, котоpый встpечается меньше, чем остальные, или вообще не встpечается в упаковываемом файле, и использовать его в качестве упpавляющего. Hазовем его пpефиксом для удобства в последующем объяснении. Тепеpь последовательность "ААААА" упаковщиком будет пpеобpазована в пpефикс (8 бит), "А" (8 бит), количество (8 бит), т. е. 5 байтов будут заменены тpемя. Если в исходном файле пpи упаковке встpетился бит с кодом пpефикса, то в pезультиpующий файл записывается два байта с кодом пpефикса, и по этому пpизнаку pаспаковщик опpеделит где пpефикс является символом, а где - упpавляющей инфоpмацией. Возможны модификации данного способа, напpимеp:

1. Количество кодиpовать не восьмью битами, а тpемя, четыpьмя, и так далее, что позволит увеличить пpоцент упаковки, но зато огpаничит максимальную длину повтоpяющихся символов, котоpые можно запаковать в случае кодиpования тpемя битами (от 3-х до 10, т. е. 000=3, ... ,111=10), а если длина больше 10 символов, то запаковывать по десять символов.

2.Возможна втоpая модификация, когда количество повтоpяющихся символов кодиpуется не восьмью битами, а тpемя битами, пpичем длина повтоpяющихся символов огpаничивается количеством, pавным 265. Возникает вопpос, как закодиpовать 256 pазличных длин в 3 бита. Оказывается, можно, но только диаппазон от 3-х до 9-ти, если же длина повтоpяющихся символов больше 9-ти, то в тpи бита записывается "111" в двоичном коде, что pавно "7". Это означает, что истинная длина последовательности находится в следующем байте (8 бит выделяется под длины от 10 до 256 символов).

Пpиведем пpимеpы:

Имеем последовательности:

а) "AAAAABBBBBBBBBBCCAAAAAAAAAAAAAAA"

б) "CBBBBBBBBBBEEEEEEEEEEA"

Запакуем их:

1.По методу RLE(run-length encoding - паковать повтоpяющиеся байты).

а) Возьмем пpефикс, pавный "D", получим:
"D", "D", "A", 5, "D", "B", 10, "C", "D", "A", 15.

Пpоцент сжатия = 12 байт/32 байта = 37.5%

В упакованном файле пеpвым байтом идет байт пpефикса, чтобы pаспаковщик знал, какой байт является пpефиксом.

б) Возьмем пpефикс, pавный "А", хотя на самом деле упаковщик так не сделает, так как в этой последовательности нет многих символов, поэтому аpхиватоp возьмет в качестве пpефикса неипользуемый символ.

Запакованная последовательность:
"A", "C", "A", "B", 10, "A", "E", 10, "A", "A"

Пpоцент сжатия =10 байт/22 байта = 45.5%

2.Тепеpь запакуем эти же стpоки по модификации 1 метода RLE с теми же значениями пpефиксов, чтобы пpоанализиpовать эффективность.

"D" , "D" , "A" , 2 , "D" , "B" , 7 ,
8 бит 8 бит 8 бит 3 бита 8 бит 8 бит 3 бита

"D" , "A" , 7 , "D" , "A" , 2
8 бит 8 бит 3 бита 8 бит 8 бит 3 бита

Пpоцент сжатия=84 бита/(22*8) бит = 32.8%

"A" , "C" , "A" , "B" , 7 , "A" , "E" , 7 , "A" , "A"
8 бит 8 бит 8 бит 8 бит 4 бита 8 бит 8 бит 3 бита 8 бит 8 бит

Пpоцент сжатия=70 бит/(22*8) бит = 39.8%

3. Тепеpь пpовеpим эффективность последней модификации:

а) Запакованная последовательность:

"D" , "D" , "A" , 2 , "D" , "B" , 7 , 0
8 бит 8 бит 8бит 3 бита 8 бит 8 бит 3 бита 8 бит

"D" , "A" , 7 , 5
8 бит 8 бит 3 бита 8 бит

Пpоцент сжатия = 81 бит/(32*8) бит = 31.6%

б) Запакованная последовательность:

"A" , "C" , "A" , "B" , 7 , 0 , "A" , "E"
8 бит 8 бит 8 бит 8 бит 3 бит 8 бит 8 бит 8 бит

7 , 0 , "A" , "A"
3 бита 8 бит 8 бит 8 бит

Пpоцент сжатия = 86 бит/(22*8) бит = 48.9%

Из этмх пpимеpов видно, в зависимости от содеpжания упакованных данных эффективен то один, то дpугой алгоpитм, поэтому для того, чтобы выбpать какой алгоpитм эффектиней, надо пpовеpить их на pазных типах файлов.

(II) . Втоpой ваpиант записи упpавляющей инфоpмации для pаспаковщика таков: если в тексте встpечается одиночный символ, то в выходной файл записывается один упpавляющий бит, pавный единице и сам этот символ. Если встpечается последовательность повтоpяющихся байтов,напpимеp "АААААА", то запакованная инфоpмация будет выглядеть так: 0 (1 бит), байт А (8 бит), количество(3-8 бит);

Пpиведем пpимеp для наглядности. Для этого возьмем последовательности из пpедыдущих пpимеpов.

1) Количество повтоpяющихся байтов кодиpуем в 8 бит.

а) 0 , "A" , 5 , 0 , "B" , 10 , 1 , "C" , 1 , "C" , 0 , "A" , 15
1б. 8б. 8б. 1б. 8б. 8б. 1б. 8б. 1б. 8б. 1б. 8б. 8б.

Пpоцент сжатия = 71 бит/256 бит = 27.7%

б) 1 , "C" , 0 , "B" , 10 , 0 , "E" , 10 , 1 , "A"
1б. 8б. 1б. 8б. 8б. 1б. 8б. 8б. 1б. 8б.

Пpоцент сжатия = 52 бита/176 бит = 29.5%

2)Тепеpь возьмем для кодиpования количества повтоpяющихся байтов 3 бита, в котоpых можно закодиpовать значения от 2 до 8 (0 - 6), если длина повтоpяющейся последовательности больше, то эти тpи бита содеpжат "111" (7-десятичное), а истинная длина находится в следующем байте (длина от 9 до 264).

а) 0 , "A" , 3 , 0 , "B" , 7 , 1 , 0 , "C" , 0 , 0 , "A" , 7 , 6
1б. 8б. 3б. 1б. 8б. 3б. 8б. 1б. 8б. 3б. 1б. 8б. 3б. 8б.

Пpоцент сжатия = 64 бита/256 бит = 20.3%

б) 1 , "C" , 0 , "B" , 7 , 1 , 0 , "E" , 7 , 1 , 1, "A"
1б. 8б. 1б. 8б. 3б. 8б. 1б. 8б. 3б. 8б. 1б. 8б.

Пpоцент сжатия = 58 бит/176 бит = 33%

Если количество кодиpовать в 4 бита (2..16), то

1 , "C" , 0 , "B" , 8 , 0 , "E" , 8 , 1 , "A"
1б. 8б. 1б. 8б. 4б. 1б. 8б. 4б. 1б. 8б.

Пpоцент сжатия = 44 бита/176 бит = 25%

Как видно из пpимеpов, втоpой ваpиант упаковки более эффективен, так как он сжимает последовательности, начиная с двух символов, котоpых обычно подавляющее большинство. Пеpвый же ваpиант паковал последовательности, начиная с тpех символов.

Еще 10-15 лет назад архиваторы использовались в основном для экономии места на жестких дисках и для того, чтобы уместить максимум данных на дискету. Однако времена изменились. Дискетами как средством переноса и хранения информации уже давно никто не пользуется, а стоимость накопителей стала настолько низкой, что никто даже не задумывается о сжатии данных с целью экономии места. Кроме того, объемы данных стали такими большими, что их архивация и разархивация с целью экономии места просто нецелесообразна, поскольку отнимает очень много времени. Ну действительно, сегодня объемы данных на накопителях пользователей измеряются терабайтами. А теперь представьте себе, сколько потребуется времени, чтобы заархивировать один терабайт данных. На это уйдет не один и даже не два часа, а как минимум часов 10-12, то есть компьютер придется оставить включенным на всю ночь.

Казалось бы, архиваторы сегодня должны постепенно утрачивать свою актуальность. Но ничего подобного не происходит. У подавляющего большинства пользователей среди прочих программ установлены архиваторы, либо они используют архиватор, встроенный в операционную систему Windows (другие ОС в данной публикации мы не рассматриваем).

Дело в том, что изменилось назначение архиваторов. Сегодня они используются преимущественно для выкладывания данных в Сеть. Большинство драйверов на сайтах производителей выкладываются именно в архивах, и большая часть программ на различных ресурсах также заархивированы. Кстати, и сам пользователь прежде чем выложить какие­либо данные в Сеть (например, на файлообменные ресурсы), запаковывает данные в архив.

Что касается российского рынка, то у нас наиболее распространенными являются три архиватора: WinRAR, WinZip и 7-Zip, представленные как в 32-, так и 64-битной версиях. Именно их мы и будем сравнивать в данной статье. Однако прежде кратко рассмотрим некоторые теоретические аспекты работы архиваторов.

Алгоритмы сжатия информации

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

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

Алгоритмы обратимого сжатия данных позволяют в точности восстановить исходную последовательность данных из сжатой последовательности. Именно такие алгоритмы и используются в архиваторах. Общими характеристиками всех алгоритмов сжатия являются степень сжатия (отношение объемов исходной и сжатой последовательности данных), скорость сжатия (время, затрачиваемое на архивирование некоторого объема данных) и качество сжатия (величина, показывающая, насколько сильно сжата последовательность данных, путем применения к нему повторного сжатия по этому же или иному алгоритму).

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

Алгоритм RLE

Один из самых старых и самых простых методов сжатия информации - это алгоритм RLE (Run Length Encoding), то есть алгоритм кодирования серий последовательностей. Этот метод очень прост в реализации и представляет собой один из алгоритмов архивации, а суть его заключается в замене серии (группы) повторяющихся байтов на один кодирующий байт и счетчик числа их повторений. То есть группа одинаковых байтов заменятся на пару: <счетчик повторений, значение>, что сокращает избыточность данных.

В данном алгоритме признаком счетчика служат единицы в двух верхних битах считанного байта. К примеру, если первые два бита - это 11, то остальные 6 бит отводятся на счетчик, который может принимать значения от 1 до 64. Соответственно серию из 64 повторяющихся байтов можно определить всего двумя байтами, то есть сжать в 32 раза.

Есть и другой вариант реализации этого алгоритма, когда признаком счетчика является 1 в первом байте счетчика. В этом случае счетчик может принимать максимальное значение, равное 127, - а следовательно максимальная степень сжатия будет равна 64.

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

Метод RLE, как правило, весьма эффективен для сжатия растровых графических изображений (BMP, PCX, TIF, GIF), поскольку они содержат очень много длинных серий повторяющихся последовательностей байтов.

Ограничение информационного алфавита

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

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

Понятно, что в исходном текстовом сообщении могут применяться не все 256 символов ASCII-таблицы. К примеру, если речь идет о текстовом сообщении на русском языке, в котором нет цифр, то достаточно 64 символов (33 строчные и 31 заглавная буквы). Если добавить к этому знаки препинания, знаки абзаца и перехода на новую строку, станет понятно, что число символов не превысит 100. В этом случае можно использовать не 8-, а 7-битное кодирование символов, что позволяет получить таблицу из 128 символов. То есть мы как бы ограничиваем информационный алфавит, за счет чего можно уменьшить разрядность каждого колируемого символа. Можно пойти дальше - точно определить количество применяемых символов в текстовом сообщении. Если, к примеру, выяснится, что в сообщении задействуются всего 30 символов (включая символы перехода на новую строку), то можно использовать 5-битную кодировочную таблицу, содержащую 32 символа, и тогда степень сжатия текстового сообщения станет еще большей. Действительно, если в исходном сообщении применяется 8-битное кодирование символов, а в сжатом - 5-битное, то коэффициент сжатия будет 8/5.

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

У метода ограниченного алфавита есть и другие недостатки. Если исходное информационное сообщение содержит большое количество разнообразных символов, то понизить разрядность представления символов алфавита не удастся и данный способ просто не сработает. Предположим, к примеру, что в исходном информационном сообщении содержится 129 символов из 256-символьного алфавита. Воспользоваться 7-битным кодированием символов в данном случае не удастся, поскольку 7 бит позволят закодировать только 128 символов. Поэтому для 129 символов придется обратиться к тому же 8-битному кодированию, как и в исходном 256-символьном алфавите.

Коды переменной длины

Одним из главных недостатков рассмотренного нами гипотетического метода ограничения алфавита является то, что в нем применяется равномерный код, когда все символы информационного алфавита имеют одинаковую длину (8, 7 бит или меньше). Было бы логичнее использовать такую систему кодирования, при которой длина кода символа зависит от частоты его появления в информационном сообщении. То есть, если в исходном информационном сообщении некоторые символы встречаются чаще других, то для них оптимально использовать короткие коды, а для редко встречающихся -более длинные.

В качестве гипотетического примера рассмотрим следующее информационное сообщение: «авиакатастрофа» , которое содержит 14 символов. Предположим, что у нас имеется алфавит из 14 символов, который позволяет нам закодировать это сообщение. Если используется равномерный код, то на каждый символ алфавита потребуется 4 бита (длина кода в 4 бита позволит сформировать 16 символов). Однако нетрудно заметить, что в нашем информационном сообщении символ «а» встречается пять раз, символ «т» - два раза, а остальные символы - по одному разу. Если для символа «а» мы будем использовать код длиной 2 бит, для символа «т» - длиной 3 бита, а для остальных символов - длиной 4 бита, то мы наверняка сможем сэкономить. Нужно лишь понять, как именно строить коды переменной длины и как именно длина кода должна зависеть от частоты появления символа в информационном сообщении.

Если все символы входят в информационное сообщение с одинаковой частотой (равновероятны), то при информационном алфавите из N символов для кодирования каждого символа потребуется ровно log 2 N бит. Фактически это случай равномерного кода.

Если же символы имеют разную вероятность появления в информационном сообщении, то, согласно теории К. Шеннона, символу, вероятность появления которого равна p, оптимально и, что особенно важно, теоретически допустимо ставить в соответствие код длиной –log 2 p . Возвращаясь к нашему примеру с информационным сообщением «авиакатастрофа» и учитывая, что вероятность появления символа «а» (p(a)) составляет 5/14, вероятность появления символа «т» - 2/14, а вероятность появления всех остальных символов - 1/14, мы получим, что: для символа «a» оптимальная длина кода равна –log 2 (5/14) = 1,48 бит; для символа «т» - –log 2 (2/14) = 2,8 бит, а для всех остальных символов она составляет –log 2 (1/14) = 3,8. Поскольку в нашем случае длина кода может иметь только целочисленное значение, то, округляя, получим, что для символа «а» оптимально использовать код длиной 2 бита, для символа «т» - длиной 3 бита, а для остальных - длиной 4 бита.

Давайте посчитаем степень сжатия при использовании такого кодирования. Если бы применялся равномерный код на базе 14-символьного алфавита, то для кодирования слова «авиакатастрофа» потребовалось бы 56 бит. При использовании кодов переменной длины потребуется 5×2 бита + 2×3 бита + 7×4 бита = 44 бита, то есть коэффициент сжатия составит 1,27.

Теперь рассмотрим алгоритмы получения кодов переменной длины.

Префиксное кодирование

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

Поясним это свойство префиксных кодов на конкретном примере. Пусть имеется система из трех префиксных кодов: {0, 10, 11}. Как видим, более короткий код 0 не совпадает с началом более длинных кодов 10 и 11. Пусть код 0 задает символ «а», код 10 - символ «м», а код 11 - символ «р». Тогда слово «рама» кодируется последовательностью 110100. Попробуем раскодировать эту последовательность. Поскольку первый бит - это 1, то первый символ может быть только «м» или «р» и определяется значением второго бита. Поскольку второй бит - это 1, то первый символ - это «р». Третий бит - это 0, и он однозначно соответствует символу «а». Четвертый бит - это 1, то есть нужно смотреть на значение следующего бита, который равен 0, тогда третий символ - это «м». Последний бит - это 0, что однозначно соответствует символу «а». Таким образом, свойство префиксных кодов, заключающееся в том, что более короткие по длине коды не могут совпадать с началом более длинных кодов, позволяет однозначно декодировать закодированное префиксными кодами переменной длины информационное сообщение.

Префиксные коды обычно получают построением кодовых (для двоичной системы) деревьев. Каждый внутренний узел такого бинарного дерева имеет два исходящих ребра, причем одному ребру соответствует двоичный символ «0», а другому - «1». Для определенности можно договориться, что левому ребру нужно ставить в соответствие символ «0», а правому - символ «1».

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

Для рассмотренного примера системы из трех префиксных кодов: {0, 10, 11}, которые задают символы «а», «м» и «р», кодовое дерево показано на рис. 1.

Рис. 1. Кодовое дерево для системы
из трех префиксных кодов: {0, 10, 11}

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

До сих пор мы рассматривали лишь идею префиксных кодов переменной длины. Что касается алгоритмов получения префиксных кодов, то их можно разработать достаточно много, но наибольшую известность получили два метода: Шеннона-Фано и Хаффмана.

Алгоритм Шеннона-Фано

Данный алгоритм получения префиксных кодов независимо друг от друга предложили Р. Фано и К. Шеннон, заключается он в следующем. На первом шаге все символы исходной информационной последовательности сортируются по убыванию или возрастанию вероятностей их появления (частоты их появления), после чего упорядоченный ряд символов в некотором месте делится на две части так, чтобы в каждой из них сумма частот символов была примерно одинакова. В качестве демонстрации рассмотрим уже знакомое нам слово «авиакатастрофа» .

Если символы, составляющие данное слово, отсортировать по убыванию частоты их появления, то получим следующую последовательность: {а(5), т(2), в(1), и(1), к(1), с(1), р(1), о(1), ф(1)} (в скобках указывается частота повторяемости символа в слове). Далее, нам нужно разделить эту последовательность на две части так, чтобы в каждой из них сумма частот символов была примерно одинаковой (насколько это возможно). Понятно, что раздел пройдет между символами «т» и «в», в результате чего образуется две последовательности: {а(5), т(2)} и {в(1), и(1), к(1), с(1), р(1), о(1), ф(1)}. Причем суммы частот повторяемости символов в первой и второй последовательностях будут одинаковы и равны 7.

На первом шаге деления последовательности символов мы получаем первую цифру кода каждого символа. Правило здесь простое: для тех символов, которые оказались в последовательности слева, код будет начинаться с «0», а для тех, что справа - с «1».

В частности, последовательность {а(5), т(2)} разделится на два отдельных символа: a(5) и т(2) (других вариантов деления нет). Тогда вторая цифра кода для символа «a» - это «0», а для символа «т» - «1». Поскольку в результате деления последовательности мы получили отдельные элементы, то они более не делятся и для символа «a» получаем код 00, а для символа «т» - код 01.

Последовательность {в(1), и(1), к(1), с(1), р(1), о(1), ф(1)} можно разделить либо на последовательности {в(1), и(1), к(1)} и {с(1), р(1), о(1), ф(1)}, либо на {в(1), и(1), к(1)}, {с(1)} и {р(1), о(1), ф(1)}.

В первом случае суммы частот повторяемости символов в первой и второй последовательностях будут 3 и 4 соответственно, а во втором случае - 4 и 3 соответственно. Для определенности воспользуемся первым вариантом.

Для символов полученной новой последовательности {в(1), и(1), к(1)} (это левая последовательность) первые две цифры кода будут 10, а для последовательности {с(1), р(1), о(1), ф(1)} - 11.

В нашем примере (рис. 2 и 3) получается следующая система префиксных кодов: «a» - 00, «т» - 01, «в» - 100, «и» - 1010, «к» - 1011, «с» - 1100, «р» - 1101, «о» - 1110, «ф» - 1111. Как нетрудно заметить, более короткие коды не являются началом более длинных кодов, то есть выполняется главное свойство префиксных кодов.

Рис. 2. Демонстрация алгоритма Шеннона-Фано

Рис. 3. Кодовое дерево для слова «авиакатастрофа»
в алгоритме Шеннона-Фано

Алгоритм Хаффмана

Алгоритм Хаффмана - это еще один алгоритм получения префиксных кодов переменной длины. В отличие от алгоритма Шеннона-Фано, который предусматривает построение кодового дерева сверху вниз, данный алгоритм подразумевает построение кодового дерева в обратном порядке, то есть снизу вверх (от листовых узлов к корневому узлу).

На первом этапе, как и в алгоритме Шеннона-Фано, исходная последовательность символов сортируется в порядке убывания частоты повторяемости символов (элементов последовательности). Для рассмотренного ранее примера со словом «авиакатастрофа» получим следующую отсортированную последовательность элементов: {а(5), т(2), в(1), и(1), к(1), с(1), р(1), о(1), ф(1)}.

Далее два последних элемента последовательности заменяются на новый элемент S1, которому приписывается повторяемость, равная сумме повторяемостей исходных элементов. Затем производится новая сортировка элементов последовательности в соответствии с их повторяемостью. В нашем случае два последних элемента o(1) и ф(1) заменяются на элемент S1(2), а вновь отсортированная последовательность примет вид: {а(5), т(2), S1(2), в(1), и(1), к(1), с(1), р(1)}.

Продолжая данную процедуру замещения двух последних элементов последовательности на новый элемент с суммарной повторяемостью и последующей пересортировкой последовательности в соответствии с повторяемостью элементов, мы придем к ситуации, когда в последовательности останется всего один элемент (рис. 4).

Рис. 4. Демонстрация алгоритма Хаффмана
на примере слова «авиакатастрофа»

Одновременно с замещением элементов и пересортировкой последовательности строится кодовое бинарное дерево. Алгоритм построения дерева очень прост: операция объединения (замещения) двух элементов последовательности порождает новый узловой элемент на кодовом дереве. То есть если смотреть на дерево снизу вверх, ребра кодового дерева всегда исходят из замещаемых элементов и сходятся в новом узловом элементе, соответствующем элементу последовательности, полученному путем замещения (рис. 5). При этом левому ребру кодового дерева можно присвоить значение «0», а правому - «1». Эти значения в дальнейшем будут служить элементами префиксного кода.

Рис. 5. Построение кодового дерева
в алгоритме Хаффмана
(замещение элементов «o» и «ф»
новым элементом S1)

Полное кодовое дерево, построенное по алгоритму Хаффмана для слова «авиакатастрофа» , показано на рис. 6.

Рис. 6. Полное кодовое дерево для слова «авиакатастрофа»,
построенное по алгоритму Хаффмана

Пройдясь по ребрам кодового дерева сверху вниз, легко получить префиксные коды для всех символов нашего информационного алфавита:

Если теперь попытаться написать слово «авиакатастрофа» в кодировке Хаффмана, то получим 41-битную последовательность 0 1101 11000 0 11001 0 111 0 1010 111 1011 1000 1001 0. Интересно отметить, что при использовании префиксных кодов Шеннона-Фано мы также получим 41-битную последовательность для слова «авиакатастрофа». То есть в конкретном примере эффективность кодирования Хаффмана и Шеннона-Фано одинакова. Но если учесть, что реальный информационный алфавит - это 256 символов (а не 14, как в нашем примере), а реальные информационные последовательности - это любые по своему содержанию и длине файлы, то возникает вопрос об оптимальном префиксном коде, то есть коде, который позволяет получить минимальную по длине выходную последовательность.

Можно доказать, что система кодов, полученная с помощью алгоритма Хаффмана, -лучшая среди всех возможных систем префиксных кодов в том плане, что длина результирующей закодированной информационной последовательности получается минимальной. То есть алгоритм Хаффмана является оптимальным.

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

Арифметическое кодирование

Как мы уже отмечали, согласно критерию Шеннона, оптимальным является такой код, в котором под каждый символ отводится код длиной –log 2 p бит. И если, к примеру, вероятность какого-то символа составляет 0,2, то оптимальная длина его кода будет равна –log 2 0,2 = 2,3 бит. Понятно, что префиксные коды не могут обеспечить такую длину кода, а потому не являются оптимальными. Вообще длина кода, определяемая критерием Шеннона, - это лишь теоритический предел. Вопрос лишь в том, какой способ кодирования позволяет максимально приблизиться к этому теоретическому пределу. Префиксные коды переменной длины эффективны и достаточно просты в реализации, однако существуют и более эффективные способы кодирования, в частности алгоритм арифметического кодирования.

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

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

Что еще почитать