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


Избавиться от нерационального кодирования нам поможет алгоритм Хаффмана (Haffman), формирующий код с наименьшей средней длиной. Суть его в следующем: все содержащиеся в файле символы записываются в список по возрастанию числа повторов. Два последних объединяются в новый составной узел, число повторов которого равно сумме повторов исходных символов. Формируется новый список, и вновь два последних значения повторов объединяются в новый узел. Данные манипуляции повторяются до тех пор, пока не останется единственное значение. И оно будет равно числу повторов всех символов, из которых состоит файл. В результате мы построим дерево, каждый узел которого имеет суммарное значение числа повторов всех узлов, находящихся ниже.
Процесс эффективного кодирования Haffman'a отображен в Таблице 1. Чтобы сформировать код для любого символа, проследите его "путь" по колонкам и строкам от начала до конца.
 c	22	22	22	22	32	42	58	100	
 e	20	20	20	22	26	32	42		
 h	16	16	16	20	22	26			
 l	16	16	16	16	20		
 a	10	10	16	16					
 k	10	10	10						
 m	4	6						
 b	2								
       
Таблица 1. Вспомогательная таблица количества повторов символов

c 01
e 00
h 111
l 110
a 100
k 1011
m 10101
b 10100
Таблица 2
В созданном дереве от ячейки, в которой указана сумма всех повторов (в данном случае она равна 100), мы ведем две ветки. Ветке с большим значением повторов мы назначаем код длиной 1, а ветке с меньшим - 2. Двигаясь по дереву сверху вниз, присваиваем каждому символу собственный уникальный код:
Именно алгоритм Хаффмана применяется для создания таких типов архивов, как PKZIP, LHA, ZOO, ARJ.
Теперь ты наверняка понял , как осуществляется сжатие файла. Если кратко, то это достигается так: назначайте самые короткие коды наиболее повторяющимся символам. А более длинные коды присваиваются символам, реже встречающимся в файле. В итоге мы получаем следующее: разные символы имеют различную длину кода, что может значительно затруднить распаковку архива. Неплохо было бы ввести разделительный символ, он будет сигнализировать о начале следующего кода. Но это невозможно по двум причинам. Во-первых, в нашем случае комбинации кодов объединяются в байты, а выбранный разделительный символ может нарушить целостность частей кода - то есть все закончится большой путаницей. Во-вторых, такой метод увеличит размер архива еще на один байт, и пользы от работы не будет.
Получается, наиболее эффективно - обеспечить синонимичное кодирование без каких-либо дополнительных символов. Итак, от нас требуется найти такой код, чтобы ни одна из его комбинаций не могла породить более длинную комбинацию, - он называется префиксным.
Например, у нас есть следующие символы и такие коды:
a 0
b 10
с 110
d 111
Таблица 3
Тогда строка 0011011111101010 может быть интерпретирована как
0 0 110 111 111 0 10 10
a a c d d a b b
Таблица 4
Но если бы у нас был такой код:
a 00
b 01
с 101
d 010
Таблица 5
Где код символа "b" может быть воспринят как начало кода символа "d", то есть три возможных варианта раскодирования строки 000101010101:
00 01 01 01 010 101
a b B b d c
Таблица 6
00 010 101 010 101
a d c d c
Таблица 7
00 01 010 101 01 01
a b d c b b
Таблица 8

Упражнения.
1. В чем заключается алгоритм Хаффмана? Где он используется?
2. С помощью таблицы 1 закодировать: а-2, в-5, с-7, п-16, е-21 (количество повторов).
3. Придумайте пример префиксного кода.
4. Раскодируйте сами строку: 0011101001111010100, если известно, что есть 4 буквы. Напишите количество их повторов.