Originally published at braginskyoleg.com.

Какая механика заложена в основу работы архиваторов? Простое сокращение подобных или витиеватое волшебство чисел, доступное техномагам. Основатель «Школы Траблшутеров» Олег Брагинский и ученик Максим Голубь разбирают сжатие данных по косточкам.

Алгоритм базовой упаковки предложил студент Массачусетского Технологического Института Дэвид Хаффман (1925-1999 г.). Появлением он обязан выбору, который поставил перед группой профессор Роберт Фано: сдавать экзамен, либо защитить диссертацию на предложенную тему.

Хаффман выбрал защиту, и преподаватель обозначил задачу, которой давно занимался сам: оптимальное кодирование информации. Найдя решение, Дэвид получил зачёт и превзошёл учителя, предложив решение открытой проблемы, ставшее основой для сжатия данных.

Предположим, что на входе есть строка вида: «АББВВГГГДДДД». Чтобы закодировать последовательность в неизменном виде понадобится словарь из пяти значений, на каждое из которых придётся по восемь байт. Итого получим 40 бит для хранения набора информации.

Наша задача построить дерево, пройдя по веткам которого, получим более короткий код искомого элемента. Значения расположим так, чтобы редко встречающиеся блоки получили более длинный шифр, а мелькающим часто вручим короткий номер. Построение проведём от веток к основанию.

Для исходной строки (1) составим полный список уникальных символов. Посчитаем частоту встречаемости в значениях. Получим: «А» встречается единожды, «Б» и «В» можно увидеть два раза, «Д» появляется в трёх местах, а «Г» как квартет музыкантов играет партию на четверых (2).

Слайд «Вводные данные»: слева исходный словарь строки «АББВВГГГДДДД», пять символов по восемь бит, итого 40 символов; справа таблица кодирования с частотами А 1, Б 2, В 2, Г 3, Д 4.

Отсортируем таблицу по возрастанию частоты встречаемости. Далее объединим два первых элемента между собой (3). Получившаяся конструкция станет родителем и получит имя «Х». Просуммируем для него частоты символов «А» и «Б»: получим значение равное трём (4).

Так как X имеет более высокое значение чем соседняя «В» равная двойке, то переместим его вправо, чтобы сохранить порядок сортировки. Для «В» и «Г» применим такое же правило группировки (5), получим узел равный пяти (6). Присвоим ему имя «Y» и перенесём в конец ряда.

Слайд «Расчёт 1/2»: четыре шага сортировки. Символы А и Б объединяются в узел X с частотой 3, затем В и Г объединяются в узел Y с частотой 5, узлы переставляются по возрастанию частоты.

Продолжим объединение для «X» и «Д» (7). Так как «Х» уже имеет под собой два дочерних элемента, то вместе с «Д» они образуют новый уровень, назовём его «Z» (8). Последний шаг, объединение «Y» и «Z». Наречём получившийся элемент литерой «T» (10).

Слайд «Расчёт 2/2»: узлы X и Д объединяются в Z, затем Y и Z объединяются в корень T с частотой 12. Таблицы показывают частоты и уровни дерева на каждом шаге.

В дереве объектов закодируем каждый элемент, проложив к нему цифровой путь. Зададим правило: если движемся от вершины по ребру влево, то значение этапа равно нулю, движение вправо: единице. При прохождении узла добавляем цифру к итоговому значению (11).

Пробежим по каждой ветке, запишем код всех значений. «X», «Y», «Z» и «T» пропускаем, являются объединяющими узлами и их судьба для нас не важна. Обратите внимание, что до частых элементов «добираемся» быстрее, а путь к редким требует нескольких переходов.

Слайд «Построение дерева»: двоичное дерево с корнем T, узлами Y, Z и X. Рёбра влево помечены нулём, вправо единицей. Коды листьев: В 00, Г 01, А 100, Б 101, Д 11.

Запишем полученные значения в итоговую таблицу и сравним с исходным словарём. При изначальных сорока битах (12) получили новый легковесный словарь с набором из двенадцати (13), что даёт экономию в двадцать восемь знаков, сохраняя драгоценное место в объёме 70%.

Слайд «Достигнутый эффект»: слева исходный словарь по восемь бит на символ, итого 40 символов; справа сжатый словарь А 100, Б 101, В 00, Г 01, Д 11, итого 12 символов.

Алгоритм Дэвида Хаффмана был разработан в середине пятидесятых годов. Благодаря простоте и постоянной выдаче оптимальных результатов взят за основу решений, требующих сжатия данных при кодировании и передачи информации во множестве программ и устройств.