
Кодирование алгоритмом Хаффмана
Эффективное кодирование или сжатие имеет своей целью компактное представление информации для её дальнейшего хранения или передачи. Одним из классов эффективных кодов являются статистические коды, к этому классу относятся и коды Хаффмана. Согласно теореме Шеннона о кодировании для канала без помех скорость передачи информации будет увеличиваться, если преобразовать сообщения от источника информации в статистически независимые, т.е. в символы с равномерной функцией распределения вероятности появления. Статистическое кодирование осуществляет такое преобразование посредством уменьшения числа символов необходимых для представления одного элемента алфавита. Для решения этой задачи алгоритм Хаффмана сопоставляет наиболее вероятным сообщениям кодовые последовательности меньшей длины, а наименее вероятным – большей длины. Входными данными для кодирования по алгоритму Хаффмана являются вероятности появления символов алфавита на выходе источника и последовательность символов, которую необходимо закодировать. Для декодирования необходимы вероятности появления (те же самые), сопоставленные соответствующим символам алфавита источника (для построения кодов) и закодированная последовательность символов. Таким образом, будем говорить о полезной нагрузке и о служебной информации необходимой для верного декодирования. Эта информация может быть как кодовым деревом, так и информацией для построения такого дерева, например, частоты или вероятности появления символов кодируемого алфавита. Хотя древовидная структура облегчает понимание принципов кодирования Хаффмана, это не самый простой путь получения кодов Хаффмана. Другой метод состоит в генерировании для всех символов кодируемого алфавита длин кодов (code length) и формировании на их основе кодов Хаффмана. Длины кодов будут занимать меньший объем, чем вероятности появления символов и тем более чем структура кодового дерева.
Для пояснения алгоритма получения кодов Хаффмана при помощи длин кодов, в качестве примера, воспользуемся следующим палиндромом:
A MAN A PLAN A CANAL PANAMA
Палиндром состоит из восьми различных символов с частотами появления, приведенными в Таблице 1.
Таблица 1
Частоты появления символов в палиндроме
Значение |
Частота |
A |
10 |
C |
1 |
L |
2 |
M |
2 |
N |
4 |
P |
2 |
Пробел |
6 |
. (точка) |
1 |
В этом алгоритме используются символы, связанные с длинами кодов и списки значений со связанными с ними частотами. Первоначально кодируемому значению присваивается длина кода равная 0, и каждое значение помещается в отдельный список, которому назначается частота, равная частоте кодируемого значения из этого списка. Для рассматриваемого палиндрома данный алгоритм образует структуру, показанную на рисунке 1.
Рис. 1 Первый этап генерирования длин кодов Хаффмана
Для получения длин кодов соединим два списка с самыми низкими частотами. При объединении двух списков частота нового списка равна сумме частот двух прежних списков. Каждый раз, при присоединении списка, частота каждого символа в списке увеличивается на единицу, а новый список перемещается на последнее место (записывается нижней строкой). Процесс повторяется до тех пор, пока не получится один список кодов. При наличии нескольких списков с наименьшей частотой, из них всегда выбирается тот список, который расположен ближе всех к концу.
Наименьшие частоты принадлежат спискам с точкой и буквой С, поэтому объединяем эти списки и увеличиваем на единицу длины кодов для двух символов (Рис.2 а).
В результате получаются четыре списка с наименьшей частотой равной 2. Выбираем два списка, ближайших к низу, и объединяем их(Рис.2 б).
Повторяя описанную выше процедуру, получаем структуры, показанные на рисунке 2 в-ж.
Рис.2 Генерирование длин кодов Хаффмана
Если отсортировать символы по длине кода, получим длины кодов, приведенные в Таблице 2. Используя алгоритм, блок-схема которого показана на рисунке 3, можно сгенерировать из отсортированного списка коды Хаффмана. Входными данными будет массив длин кодов Хаффмана, подобных тем, что приведены в Таблице 1, а выходными массив кодов Хаффмана, сгенерированных для длин кодов.
Таблица 2
Символы палиндрома, отсортированные по длине кода
Символ |
Код длины |
A |
1 |
Пробел |
3 |
N |
3 |
L |
4 |
M |
4 |
P |
4 |
C |
5 |
. (точка) |
5 |
Для того, что бы алгоритм корректно завершил свою работу к массиву длин кодов нужно добавить нулевую длину на последнюю позицию. Поэтому в примере работы данного алгоритма, рассмотренном ниже, входной массив будет содержать 9 позиций, а не 8.
Рис.3 Блок-схема алгоритма генерирования кодов Хаффмана по длинам кодов
На рисунке 3 приняты следующие обозначения:
MD – массив длин кодов
MK – массив кодов Хаффмана
с – текущий ход Хаффмана
s – текущая длина кода Хаффмана
k – индекс массива длин
== - равно
!= - неравно
= присвоить
← - увеличить массив на один элемент справа и добавить на это место указанное значение
++ - увеличить на единицу
<<= - сдвинуть значение влево на указанную величину с добавлением нулей справа.
Далее рассмотрим пример построения кодов Хаффмана по длинам с использованием алгоритма, представленного на рисунке 3.
Входные данные: MD[9]={1,3,3,4,4,4,5,5,0}; MK[0]={};
c=0;s=1;k=0;
MD[0]==1 → MK={0};c=1;k=1;
MD[1]!=1
MD[1]!=0
c=10;s=2;
MD[1]!=2 → c=100;s=3;
MD[1]==3
MD[1]==3 → MK={0,100};c=101;k=2;
MD[2]==3 → MK={0,100,101};c=110;k=3;
MD[3]!=3
MD[3]!=0
c=1100;s=4;
MD[3]==4
MD[3]==4 → MK={0,100,101,1100};c=1101;k=4;
MD[4]==4 → MK={0,100,101,1100,1101};c=1110;k=5;
MD[5]==4 → MK={0,100,101,1100,1101,1110};c=1111;k=6;
MD[6]!=4
MD[6]!=0
c=11110;s=5;
MD[6]==5
MD[6]==5 → MK={0,100,101,1100,1101,1110,11110};c=11111;k=7;
MD[7]==5 → MK={0,100,101,1100,1101,1110,11110,11111};c=100000;k=8;
MD[8]!=5
MD[8]==0 → конец
Выходные данные: MK={0,100,101,1100,1101,1110,11110,11111};
Таким образом, служебная информация это список символов кодируемого алфавита плюс список длин кодов. Однако на декодер можно передавать не сам список длин, а список счетчиков длин, т.е. список количества появлений каждой длины от длины равной 1 до максимальной длины. Построим список счетчиков длин для нашего примера (Таблица 3):
Таблица 3
Пример построения списка счетчика длин
Код длины |
1 |
3 |
3 |
4 |
4 |
4 |
5 |
5 |
Список счетчиков длин |
|
Длина |
Счетчик |
1 |
1 |
2 |
0 |
3 |
2 |
4 |
3 |
5 |
2 |
Вместо частот появления символов можно использовать вероятности появления. Если заданы только частоты появления, то, зная суммарное количество символов в кодируемой последовательности можно перейти к вероятностям, разделив частоту появления каждого символа на общее количество.
Приведенный алгоритм, так же как и классический алгоритм Хаффмана позволяет построить совокупность кодовых комбинаций различной длины обладающих свойством преффиксности, которое гласит: никакая кодовая комбинация не может являться началом другой более длинной кодовой комбинации.
Если говорить о кодировании алгоритмом Хаффмана применительно к черно-белым изображениям, то возникает вопрос, каким образом выбирать алфавит источника-изображения. Так, как пиксель может принимать только два значения, то при выборе в качестве элемента алфавита пикселя, алгоритм Хаффмана построит две кодовые комбинации: «0» и «1». Как не сложно заметить, никакого сжатия в этом случае не будет. Для преодоления этой сложности будем объединять соседние пиксели в квадратные блоки, так, чтобы соседние блоки соприкасались сторонами, и вся плоскость изображения была ими покрыта. Для определённости, в данной лабораторной работе будем использовать квадратные блоки со стороной в 3 пикселя. Тогда, в качестве символа алфавита источника будет выступать уже блок. Максимальное количество различных символов в таком алфавите будет равно 512 (каждый блок со стороной 3 пикселя содержит 9 пикселей внутри, а число различных комбинаций, притом, что каждый пиксель принимает два значения, это 2 в степени 9), такой прием называется укрупнением алфавита.