Адаптивное кодирование Хаффмана (также называемое динамическим кодированием Хаффмана ) — это адаптивный метод кодирования , основанный на кодировании Хаффмана . Он позволяет строить код по мере передачи символов, не имея начальных знаний об исходном распределении, что позволяет выполнять однопроходное кодирование и адаптироваться к изменяющимся условиям в данных. [1]
Преимущество однопроходной процедуры заключается в том, что исходный код можно кодировать в реальном времени, хотя он становится более чувствительным к ошибкам передачи, поскольку даже одна потеря портит весь код, требуя обнаружения и исправления ошибок .
Существует ряд реализаций этого метода, наиболее известными из которых являются алгоритм FGK ( Фаллер - Галлагер - Кнут ) и Виттер .
Это онлайн-метод кодирования, основанный на кодировании Хаффмана. Не имея начальных знаний о частотах появления, он позволяет динамически корректировать дерево Хаффмана по мере передачи данных. В дереве FGK Хаффмана специальный внешний узел, называемый 0-узлом , используется для идентификации нового поступающего символа. То есть, всякий раз, когда встречаются новые данные, выводится путь к 0-узлу, за которым следуют данные. Для символа, поступившего в прошлом, просто выводится путь данных в текущем дереве Хаффмана. Самое главное, что мы должны корректировать дерево FGK Хаффмана, если это необходимо, и, наконец, обновлять частоту связанных узлов. По мере увеличения частоты данных свойство родства дерева Хаффмана может быть нарушено. Корректировка запускается по этой причине. Она выполняется путем последовательных обменов узлов, поддеревьев или того и другого. Узел данных меняется местами с узлом наивысшего порядка той же частоты в дереве Хаффмана (или поддеревом, корнем которого является узел наивысшего порядка). Все узлы-предки узла также должны обрабатываться таким же образом.
Поскольку алгоритм FGK имеет некоторые недостатки, связанные с заменой узлов или поддеревьев, Виттер предложил другой алгоритм для его улучшения.
Некоторые важные термины и ограничения:
Блоки связаны между собой в порядке возрастания их веса.
Листовой блок всегда предшествует внутреннему блоку того же веса, тем самым сохраняя инвариантность.
NYT (еще не передано) — это специальный узел, используемый для представления символов, которые «еще не переданы» .
Алгоритм добавления символа : лист_для_приращения := NULL p := указатель на конечный узел, содержащий следующий символ если (p — NYT), то Расширить p, добавив двух потомков Левый потомок становится новым NYT, а правый потомок — новым конечным узлом символа. p := родительский узел нового символа leaf_to_increment := Правый потомок p еще Поменять p с лидером его блока если (новый p является родственным NYT), то лист_для_приращения := p p := родитель p пока (p ≠ NULL) делать Слайд_И_Инкремент(p) если (leaf_to_increment != NULL) тогда Скольжение_и_увеличение(leaf_to_increment)
функция Slide_And_Increment(p) — это previous_p := parent p если (p — внутренний узел), то Сдвиньте p в дереве выше листовых узлов веса wt + 1 увеличить вес p на 1 p := previous_p иначе Сдвиньте p в дереве выше внутренних узлов веса wt увеличить вес p на 1 p := новый родительский элемент p .
Кодер и декодер начинают только с корневого узла, который имеет максимальный номер. В начале это наш начальный узел NYT.
Когда мы передаем символ NYT, нам необходимо передать код для узла NYT, а затем для его общего кода.
Для каждого символа, который уже есть в дереве, нам нужно передать только код его конечного узла.
Кодировка «abb» дает 01100001 001100010 11.
Шаг 1:
Начните с пустого дерева.
Для «а» передайте его двоичный код.
Шаг 2:
NYT порождает два дочерних узла: 254 и 255, оба с весом 0. Увеличьте вес для корня и 255. Код для «a», связанный с узлом 255, равен 1.
Для «b» передайте 0 (для узла NYT), а затем его двоичный код.
Шаг 3:
NYT порождает два дочерних узла: 252 для NYT и 253 для листового узла, оба с весом 0. Увеличьте веса для 253, 254 и корня. Чтобы сохранить инвариант Виттера, что все листья веса w предшествуют (в неявной нумерации) всем внутренним узлам веса w, ветвь, начинающаяся с узла 254, должна быть заменена (с точки зрения символов и весов, но не порядка номеров) с узлом 255. Код для "b" - 11.
Для второго «б» передайте 11.
Для удобства объяснения этот шаг не полностью следует алгоритму Виттера [2] , но эффекты эквивалентны.
Шаг 4:
Перейдите к листовому узлу 253. Обратите внимание, что у нас есть два блока с весом 1. Узел 253 и 254 — это один блок (состоящий из листьев), узел 255 — это другой блок (состоящий из внутренних узлов). Для узла 253 наибольшее число в его блоке — 254, поэтому поменяйте веса и символы узлов 253 и 254. Теперь узел 254 и ветвь, начинающаяся с узла 255, удовлетворяют условию SlideAndIncrement [2] и, следовательно, должны быть поменяны местами. Наконец, увеличьте вес узлов 255 и 256.
Будущий код для «b» — 1, а для «a» — 01, что отражает их частоту.