Реалізація коду Хафмена

Хай є джерело даних, яке передає символи з різним ступенем імовірності, тобто кожному відповідає своя імовірність (або частота) , причому існує хоча б одна пара і , , такі, що і не рівні. Таким чином утворюється набір частот при чому , оскільки передавач не передає більше ніяких символів окрім як .

Наша задача – підібрати такі кодові символи з довжинами щоб середня довжина кодового символу не перевищувала середньої довжини початкового символу. При цьому потрібно враховувати умову, що якщо і , то .

Хафмен запропонував будувати дерево, в якому вузли з найменшою імовірністю якнайдальше віддалені від кореня. Звідси і витікає алгоритм побудови дерева чи алгоритм кодування:

1. Вибрати два символи і , такі, що і зі всього списку є мінімальними.

2. Звести гілки дерева від цих двох елементів в одну точку з імовірністю , помітивши одну гілку нулем, а іншу – одиницею (за власним розсудом).

3. Повторити пункт 1 з урахуванням нової точки замість і , якщо кількість точок, що вийшли, більше одиниці. Інакше ми досягли кореня дерева.

Приклад.Тепер спробуємо скористатися одержаною теорією і закодувати інформацію, передану джерелом, на прикладі семи символів.

Розберемо детально перший цикл. На малюнку зображена таблиця, в якій кожному символу і відповідає своя імовірність (частота).

Згідно пункту 1 ми вибираємо два символи з таблиці з якнайменшою імовірністю. У нашому випадку це і . Згідно пункту 2 зводимо гілки дерева від і у одну точку і позначаємо гілку, що веде до , одиницею, а гілку, що веде до , – нулем. Над новою точкою приписуємо її імовірність (в даному випадку - 0.03). Надалі дії повторюються вже з урахуванням нової точки і без урахування і .

 

Після багатократного повторення висловлених дій будується наступне дерево:

По побудованому дереву можна визначити значення кодів , здійснюючи спуск від коріння до відповідного елементу , при цьому приписуючи до одержуваної послідовності при проходженні кожної гілки нуль або одиницю (залежно від того, як іменується конкретна гілка). Таким чином таблиця кодів виглядає таким чином:

 

 

0,01
0,40
0,08
0,02
0,10
0,35
0,04

Тепер спробуємо закодувати послідовність з символів.

Хай символу відповідає (як приклад) число і. Хай є послідовність 12672262. Потрібно одержати результуючий двійковий код.

Для кодування можна використовувати таблицю кодових символів із врахуванням, що відповідає символу . У такому разі код для цифри 1 буде послідовністю 011111, для цифри 2 – 1, для цифри 6 – 00, а для цифри 7 – 01110. Таким чином, одержуємо наступний результат:

Дані Довжина коду
Початкові 001 010 110 111 010 010 110 010 24 біт
Кодовані 011111 1 00 01110 1 1 00 1 19 біт

В результаті кодування ми виграли 5 біт і записали послідовність 19 бітами замість 24.

 

Ентропію для нашого випадку:

.

Ентропія має чудову властивість: вона дорівнює мінімальній допустимій середній довжині кодового символу у бітах. Сама ж середня довжина кодового символу обчислюється по формулі:

.

Підставляючи значення у формули і , одержуємо наступні результати:

,

.

Величини і дуже близькі, що говорить про реальний виграш у виборі алгоритму. Тепер порівняємо середню довжину початкового символу і середню довжину кодового символу через коефіцієнт стиснення – відношення початкової довжини символу до середньої довжини стисненого символу :

.

Таким чином, ми одержали стиснення в співвідношенні 1:1,429, що дуже непогане.

І наприкінці, вирішимо останню задачу: дешифровка послідовності бітів.

Хай для нашої ситуації є послідовність бітів:

001101100001110001000111111.

Необхідно визначити початковий код, тобто декодувати цю послідовність.

Звичайно, в такій ситуації можна скористатися таблицею кодів, але це достатньо незручно, оскільки довжина кодових символів непостійна. Набагато зручніше здійснити спуск по дереву (починаючи з коріння) за наступним правилом:

1. Початкова точка – корінь дерева.

2. Прочитати новий біт. Якщо він нуль, то пройти по гілці, поміченій нулем, інакше - одиницею.

3. Якщо точка, в яку ми потрапили, кінцева, то ми визначили кодовий символ, який слідує записати і повернутися до пункту 1. Інакше слід повторити пункт 2.

Розглянемо приклад декодування першого символу. Ми знаходимося в точці з імовірністю 1,00 (коріння дерева), прочитуємо перший біт послідовності і відправляємося по гілці, поміченій нулем, в точку з імовірністю 0,60. Оскільки ця точка не є кінцевою в дереві, то прочитуємо наступний біт, який теж рівний нулю, і відправляємося по гілці, поміченій нулем, в точку , яка є кінцевою. Ми дешифрували символ – це число 6. Записуємо його і повертаємося в початковий стан (переміщаємося в коріння).

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

Дані Довжина коду
Кодовані 00 1 1 0110 00 01110 00 1 00 011111 1 27 біт
Початкові 6 2 2 3 6 7 6 2 6 1 2 11∙3=33 біт

 

В даному випадку виграш склав 6 біт при достатньо невеликій довжині послідовності.

 

Слід зазначити, що метод Хафмена застосовний для джерела повідомлень, що з’являються з будь-якою імовірністю, а не тільки з імовірністю цілого ступеня основи коду.

Приклад 2.Задано ансамбль повідомлень:

Побудувати двійковий код Хафмена.

Кодове дерево для даного коду представлене на рис. 2.

2. Кодове дерево для коду за прикладом 2