|
||||||||||||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Код Хаффмана. Симаков Александр, xander@online.ru Сыктывкарский Государственный Университет Кафедра Прикладной Математики 13 ноября 2002 года
Код Хаффмана Симаков Александр, xander@online.ru Введение В этой статье мы рассмотрим один из самых распространенных методов сжатия данных. Речь пойдет о коде Хаффмана (Huffman code) или минимально-избыточном префиксном коде (minimum-redundancy prefix code). Мы начнем с основных идей кода Хаффмана, исследуем ряд важных свойств и затем приведем полную реализацию кодера и декодера, построенных на идеях, изложенных в этой статье. Идея, лежащая в основе кода Хаффмана, достаточно проста. Вместо того чтобы кодировать все символы одинаковым числом бит (как это сделано, например, в ASCII кодировке, где на каждый символ отводится ровно по 8 бит), будем кодировать символы, которые встречаются чаще, меньшим числом бит, чем те, которые встречаются реже. Более того, потребуем, чтобы код был оптимален или, другими словами, минимально-избыточен. Первым такой алгоритм опубликовал Дэвид Хаффман (David Huffman) [1] в 1952 году. Алгоритм Хаффмана двухпроходный. На первом проходе строится частотный словарь и генерируются коды. На втором проходе происходит непосредственно кодирование. Стоит отметить, что за 50 лет со дня опубликования, код Хаффмана ничуть не потерял своей актуальности и значимости. Так с уверенностью можно сказать, что мы сталкиваемся с ним, в той или иной форме (дело в том, что код Хаффмана редко используется отдельно, чаще работая в связке с другими алгоритмами), практически каждый раз, когда архивируем файлы, смотрим фотографии, фильмы, посылаем факс или слушаем музыку. Код Хаффмана Определение 1: Пусть A={a1,a2,...,an} - алфавит из n различных символов, W={w1,w2,...,wn} - соответствующий ему набор положительных целых весов. Тогда набор бинарных кодов C={c1,c2,...,cn}, такой что:
называется минимально-избыточным префиксным кодом или иначе кодом Хаффмана. Замечания: 1. Свойство (1) называется свойством префиксности. Оно позволяет однозначно декодировать коды переменной длины. 2. Сумму в свойстве (2) можно трактовать как размер закодированных данных в битах. На практике это очень удобно, т.к. позволяет оценить степень сжатия не прибегая непосредственно к кодированию. 3. В дальнейшем, чтобы избежать недоразумений, под кодом будем понимать битовую строку определенной длины, а под минимально-избыточным кодом или кодом Хаффмана - множество кодов (битовых строк), соответствующих определенным символам и обладающих определенными свойствами. Известно, что любому бинарному префиксному коду соответствует определенное бинарное дерево. Определение 2: Бинарное дерево, соответствующее коду Хаффмана, будем называть деревом Хаффмана. Задача построения кода Хаффмана равносильна задаче построения соответствующего ему дерева. Приведем общую схему построения дерева Хаффмана: 1. Составим список кодируемых символов (при этом будем рассматривать каждый символ как одноэлементное бинарное дерево, вес которого равен весу символа). 2. Из списка выберем 2 узла с наименьшим весом. 3. Сформируем новый узел и присоединим к нему, в качестве дочерних, два узла выбранных из списка. При этом вес сформированного узла положим равным сумме весов дочерних узлов. 4. Добавим сформированный узел к списку. 5. Если в списке больше одного узла, то повторить 2-5. Приведем пример: построим дерево Хаффмана для сообщения S="A H F B H C E H E H C E A H D C E E H H H C H H H D E G H G G E H C H H". Для начала введем несколько обозначений: 1. Символы кодируемого алфавита будем выделять жирным шрифтом: A, B, C. 2. Веса узлов будем обозначать нижними индексами: A 5, B 3, C 7. 3. Составные узлы будем заключать в скобки: ((A 5+ B 3)8+ C 7)15. Итак, в нашем случае A={ A, B, C, D, E, F, G, H }, W={2, 1, 5, 2, 7, 1, 3, 15}. 1. A 2 B 1 C 5 D 2 E 7 F 1 G 3 H 15 2. A 2 C 5 D 2 E 7 G 3 H 15 (F 1+ B 1)2 3. C 5 E 7 G 3 H 15 (F 1+ B 1)2 (A 2+ D 2)4 4. C 5 E 7 H 15 (A 2+ D 2)4 ((F 1+ B 1)2+ G 3)5 5. E 7 H 15 ((F 1+ B 1)2+ G 3)5 (C 5+(A 2+ D 2)4)9 6. H 15 (C 5+(A 2+ D 2)4)9 (((F 1+ B 1)2+ G 3) 5+ E 7)12 7. H 15 ((C 5+(A 2+ D 2)4) 9+(((F 1+ B 1)2+ G 3) 5+ E 7)12)21 8. (((C 5+(A 2+ D 2)4) 9+(((F 1+ B 1)2+ G 3) 5+ E 7)12)21+ H 15)36 В списке, как и требовалось, остался всего один узел. Дерево Хаффмана построено. Теперь запишем его в более привычном для нас виде. ROOT /\ 0 1 / \ /\ H / \ / \ / \ 0 1 / \ / \ / \ / \ /\ /\ 0 1 0 1 / \ / \ C /\ /\ E 0 1 0 1 / \ / \ A D /\ G 0 1 / \ F BЛистовые узлы дерева Хаффмана соответствуют символам кодируемого алфавита. Глубина листовых узлов равна длине кода соответствующих символов. Путь от корня дерева к листовому узлу можно представить в виде битовой строки, в которой "0" соответствует выбору левого поддерева, а "1" - правого. Используя этот механизм, мы без труда можем присвоить коды всем символам кодируемого алфавита. Выпишем, к примеру, коды для всех символов в нашем примере:
Теперь у нас есть все необходимое для того чтобы закодировать сообщение S. Достаточно просто заменить каждый символ соответствующим ему кодом: S/="0010 1 01000 01001 1 000 011 1 011 1 000 011 0010 1 0011 000 011 011 1 1 1 000 1 1 1 0011 011 0101 1 0101 0101 011 1 000 1 1". Оценим теперь степень сжатия. В исходном сообщении S было 36 символов, на каждый из которых отводилось по [log2|A|]=3 бита (здесь и далее будем понимать квадратные скобки [] как целую часть, округленную в положительную сторону, т.е. [3,018]=4). Таким образом, размер S равен 36*3=108 бит Размер закодированного сообщения S/ можно получить воспользовавшись замечанием 2 к определению 1, или непосредственно, подсчитав количество бит в S/. И в том и другом случае мы получим 89 бит. Итак, нам удалось сжать 108 в 89 бит. Теперь декодируем сообщение S/. Начиная с корня дерева будем двигаться вниз, выбирая левое поддерево, если очередной бит в потоке равен "0", и правое - если "1". Дойдя до листового узла мы декодируем соответствующий ему символ. Ясно, что следуя этому алгоритму мы в точности получим исходное сообщение S. Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.004 сек.) |