Код Хаффмана

Код Хаффмана (Дэвид Хаффман, 1952) — способ сжатия без потерь: частым символам достаются короткие кодовые слова, редким — длинные. Среди всех префиксных кодов он даёт наименьшую среднюю длину, поэтому его используют форматы DEFLATE (ZIP, PNG), JPEG и MP3.

Префиксные коды

Определение

Код называется префиксным, если ни одно кодовое слово не является началом (префиксом) другого.

Префиксный код декодируется однозначно и без разделителей: читаем биты слева направо, пока прочитанное не совпадёт с каким-то кодовым словом, — это слово единственное. Код {0, 01, 11} не префиксный: «0» — начало «01», и строку «011» нельзя прочитать, не заглянув вперёд.

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

Неравенство Крафта

Двоичный префиксный код с длинами слов l_1, …, l_N существует тогда и только тогда, когда

Σ 2^(−l_i) ≤ 1

Идея доказательства. Достроим дерево до полного глубины l_max. Слово длины l_i «занимает» все 2^(l_max − l_i) листьев своего поддерева, и у разных слов эти множества не пересекаются. Значит, Σ 2^(l_max − l_i) ≤ 2^(l_max). Обратно, если неравенство выполнено, раздаём слова в порядке возрастания длины, каждый раз занимая самое левое свободное поддерево.

Средняя длина и энтропия

Если символ a_i встречается с вероятностью p_i и кодируется словом длины l_i, средняя длина кода

L = Σ p_i·l_i (бит на символ)
Теорема Шеннона для кода Хаффмана
H ≤ L < H + 1,

где H = −Σ p_i·log₂ p_i — энтропия источника.

Нижняя граница верна для любого префиксного кода (следует из неравенства Крафта). Верхняя: длины l_i = ⌈−log₂ p_i⌉ удовлетворяют неравенству Крафта и дают L < H + 1, а код Хаффмана не хуже любого префиксного кода.

Алгоритм

  1. Для каждого символа создаём лист с весом, равным его частоте.
  2. Пока узлов больше одного: берём два узла с наименьшими весами и объединяем их в новый узел, вес которого — сумма весов. Одному потомку приписываем ребро «0», другому — «1».
  3. Оставшийся узел — корень. Код символа — последовательность меток на пути от корня до его листа.

Удобная структура данных — очередь с приоритетами (куча): N − 1 объединение, каждое за O(log N), итого O(N log N).

Пример: «абракадабра»

Пример

Частоты: а — 5, б — 2, р — 2, к — 1, д — 1 (всего 11 символов). Объединения:

ШагОбъединяемНовый весОчередь после шага
1к (1) + д (1)2а 5, б 2, р 2, (кд) 2
2б (2) + р (2)4а 5, (бр) 4, (кд) 2
3(кд) 2 + (бр) 46а 5, (кдбр) 6
4а (5) + (кдбр) 611корень
СимволЧастотаКодДлина
а501
к11003
д11013
б21103
р21113

Длина закодированного слова 5·1 + (1 + 1 + 2 + 2)·3 = 23 бита вместо 33 при равномерном 3-битном коде. Средняя длина L = 23/11 ≈ 2,09 бита, энтропия H ≈ 2,04 бита, эффективность кода H/L ≈ 97,6%.

Декодирование «01101110»: 0 → а, 110 → б, 111 → р, 0 → а — получаем «абра».

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

Почему код оптимален

Теорема

Код Хаффмана имеет наименьшую среднюю длину среди всех префиксных кодов для данных вероятностей.

Доказательство (индукция по числу символов N; пусть p_1 ≥ … ≥ p_N).

  1. В оптимальном коде более вероятный символ не длиннее менее вероятного: иначе обмен их слов уменьшит L.
  2. В дереве оптимального кода каждый внутренний узел имеет двух потомков (иначе узел можно «схлопнуть» и укоротить слова). Поэтому на самой глубокой позиции есть два листа-брата, и в них можно поместить два самых редких символа a_(N−1), a_N.
  3. Склеим эти два листа в один символ с вероятностью p_(N−1) + p_N. Для любого кода, где они братья, L = L' + p_(N−1) + p_N, где L' — средняя длина кода для N − 1 символов. Добавка не зависит от кода, поэтому минимизировать L — то же, что минимизировать L', а это по предположению индукции делает код Хаффмана.

Практические замечания

  • Таблицу кодов нужно передать вместе с сообщением (или договориться о ней заранее) — для коротких сообщений это съедает весь выигрыш. В лаборатории можно взять частоты из самого сообщения или из файла со статистикой русского текста («Война и мир»).
  • Код Хаффмана тратит целое число бит на символ, поэтому при очень неравномерных вероятностях (например, p = 0,99) он заметно хуже энтропии. Арифметическое кодирование обходит это ограничение.
  • Одна ошибка в канале сбивает синхронизацию декодера: префиксные коды не защищают от помех, для этого нужны помехоустойчивые коды.
В лаборатории

Введите сообщение — появятся таблица кодов, трассировка кодирования и декодирования и дерево кода. Сравните результат для частот «из сообщения» и «из frequency.json». Открыть код Хаффмана →

Вопросы для самопроверки

  1. Является ли код {0, 10, 110, 111} префиксным? Выполняется ли для него неравенство Крафта с равенством?
    ОтветДа; 1/2 + 1/4 + 1/8 + 1/8 = 1 — дерево полное.
  2. Постройте код Хаффмана для частот A — 4, B — 2, C — 1, D — 1 и найдите среднюю длину.
    ОтветДлины 1, 2, 3, 3; L = (4 + 4 + 3 + 3)/8 = 1,75 бита — совпадает с энтропией, так как все вероятности — степени 1/2.
  3. Когда средняя длина кода Хаффмана в точности равна энтропии?
    ОтветКогда все вероятности имеют вид 2^(−k).