Оптимальное кодирование
Оптимальным кодированием называется процедура преобразования символов первичного алфавита m1 в кодовые слова во вторичном алфавите m2, при котором средняя длина сообщений во вторичном алфавите имеет минимально возможную длину.
Коды, представляющие первичные алфавиты с неравномерным распределением символов, имеющие среднюю минимальную длину кодового слова во вторичном алфавите, называются оптимальными неравномерными кодами (ОНК).
Эффективность ОНК оценивают при помощи двух коэффициентов:
1. коэффициента статического сжатия
,
который характеризует уменьшение количества двоичных знаков на символ сообщения при применении ОНК по сравнению с применением методов нестатистического кодирования.
2. коэффициента относительной эффективности
,
который показывает, насколько используется статическая избыточность передаваемого сообщения.
Из свойств оптимальных кодов вытекают принципы их построения:
-
выбор каждого кодового слова необходимо производить так, чтобы содержащееся в нем количество информации было максимальным,
-
буквам первичного алфавита, имеющим большую вероятность, присваиваются более короткие кодовые слова во вторичном алфавите.
Принципы оптимального кодирования определяют методики построения оптимальных кодов.
-
Построение ОНК по методике Шеннона-Фано для ансамбля из M сообщений сводится к следующей процедуре:
-
множество из M сообщений располагают в порядке убывания вероятностей;
-
первоначальный ансамбль кодируемых сигналов разбивают на две группы таким образом, чтобы суммарные вероятности сообщений обеих групп были по возможности равны;
-
первой группе присваивают символ 0, второй группе символ 1;
-
каждую из подгрупп делят на две группы так, чтобы их суммарные вероятности были по возможности равны;
-
первым подгруппам каждой из групп вновь присваивают 0, а вторым - 1, в результате чего получают вторые цифры кода. Затем каждую из четырех подгрупп вновь делят на равные (с точки зрения суммарной вероятности) части и т. д. До тех пор, пока в каждой из подгрупп останется по одной букве.
Алгоритм 2.1.1 – Алгоритм построения кода, близкого к оптимальному
Вход : Р : array [1..n] of real - массив вероятностей появления букв в сообщении, упорядоченный по убыванию; 1 Р [1] … Р [n] > 0,
Р [1] + … + Р [n] = 1.
Выход : С : array [1..n, 1..L] of 0..1 - массив элементарных кодов.
Fano (1, n, 0) {вызов рекурсивной процедуры Fano}
Основная работа по построению элементарных кодов выполняется следующей рекурсивной процедурой Fano.
Вход: b - индекс начала обрабатываемой части массива P,
e - индекс конца обрабатываемой части массива P,
k - длина уже построенных кодов в обрабатываемой части массива C.
Выход: заполненный массив С.
if e > b then
k : = k + 1 {место для очередного разряда в коде}
m : = Med (b, e) {деление массива на две части}
for i from b to e do
C [i, k] : = i > m {в первой части добавляем 0, во второй – 1}
end for
Fano (b, m, k) {обработка первой части}
Fano (m + 1, е, k) {обработка второй части}
end if
Функция Med находит медиану указанной части массива Р [b..e], т.е. определяет такой индекс m (b ≤ m < e), что сумма элементов Р [b..m] наиболее близка к сумме элементов Р [m + 1..e].
Примечание. При каждом удлинении кодов в одной части коды удлиняются нулями, а в другой части – единицами. Таким образом, коды одной части не могут быть префиксами другой. Удлинение кода заканчивается тогда и только тогда, когда длина части равна 1, то есть остается единственный код. Таким образом, схема построения префиксная, а потому разделимая, т.е. коды не требуют разделителя.
Пример: Построим оптимальный код сообщения, состоющего из восьми равновероятных букв.
Решение. Так вероятности данного ансамбля сообщений равны p1 = = p2 = ...= p8 = 2-3 и порядок их расположения не играет роли, то расположим их так, как показано в таблице 2.1.1. Затем разбиваем данное множество на две равновероятные группы. Первой группе в качестве первого символа кодовых слов присваиваем 0, а второй - 1. Во второй колонке таблицы записываем четыре нуля и четыре единицы. После чего разбиваем каждую из групп еще на две равновероятные подгруппы. Затем каждой первой подгруппе присваиваем 0, а второй - 1 и записываем в третью колонку таблицы. Далее каждую из четырех подгрупп разбиваем на две равновероятные части и первой из них присваиваем 0, а второй - 1. Таким образом в четвертой колонке появится значение третьего символа кодовых слов.
Таблица 2.1.1 – Оптимальный код равновероятных букв
Буква | Кодовое слово полученное после разбиения | ||
| первого | второго | третьего |
А1 А2 А3 А4 А5 А6 А7 А8 | 0 0 0 0 1 1 1 1 | 0 0 1 1 0 0 1 1 | 0 1 0 1 0 1 0 1 |
Проверка оптимальности кода осуществляется путем сравнения энтропии кодируемого (первичного) алфавита со средней длиной кодового слова во вторичном алфавите.
Для рассматриваемого примера энтропия источника сообщений
H = log2 N = log2 8=3 бит/символ
а среднее число двоичных знаков на букву кода
бит
где li - длина i-ой кодовой комбинации; pi - вероятность появления i-го символа комбинации длиной в li.
Таким образом, H = L, т. е. код является оптимальным для данного ансамбля сообщений.
Вывод: Для ансамблей равновероятных сообщений оптимальным является равномерный код. Если число исходных элементов ансамбля равно целой степени двух, то всегда H = L.
Пример. Первичный алфавит состоит из 8 символов со следующими вероятностями появления: a1 = 0,5; a2 = 0,25; a3 = 0,098; a4 = = 0,052; a5 = 0,04; a6 = 0,03; a7 = 0,019; a8 = 0,011. Построить ОНК по методу Шеннона - Фано и подсчитать коэффициенты.
Решение проиллюстрируем в таблице 2.1.2.
Таблица 2.1.2 – Оптимальный код неравновероятных букв
ai | pi | Кодовое слово после разбиения | Знаков | lipi | |||||
|
| 1 | 2 | 3 | 4 | 5 | 6 |
|
|
1 | 0,5 | 0 | - | - | - | - | - | 1 | 0,5 |
2 | 0,25 | 1 | 0 | - | - | - | - | 2 | 0,5 |
3 | 0,098 | 1 | 1 | 0 | 0 | - | - | 4 | 0,392 |
4 | 0,052 | 1 | 1 | 0 | 1 | - | - | 4 | 0,208 |
5 | 0,04 | 1 | 1 | 1 | 0 | - | - | 4 | 0,16 |
6 | 0,03 | 1 | 1 | 1 | 1 | 0 | - | 5 | 0,15 |
7 | 0,019 | 1 | 1 | 1 | 1 | 1 | 0 | 6 | 0,114 |
8 | 0,011 | 1 | 1 | 1 | 1 | 1 | 1 | 6 | 0,066 |
Недостатком методики Шеннона – Фано является неоднозначность построения ОНК. В методике Хаффмена этого недостатка нет.
ІІ. Хаффмен предложил следующий метод построения ОНК:
-
Символы первичного алфавита выписываются в порядке убывания вероятностей.
-
Последние n0 символов, где 2 n0 m и N - n0 / m - 1 - целое число, объединяют в некоторый новый символ с вероятностью, равной сумме вероятностей объединяемых символов.
-
Последние символы с учетом образованного символа вновь объединяют и получают новый, вспомогательный, символ.
-
Опять выписывают символы в порядке убывания вероятноьстей с учетом вспомогательного символа и т. д. До тех пор, пока вероятности m оставшихся символов после N - n0/m - 1-го выписывания не дадут в сумме 1.
На практике обычно не производят многократного выписывания вероятностей символов, а обходятся элементарными геометрическими построениями, суть которых для кодов с числом качественных признаков m = 2 сводится к тому, что символы кодируемого алфавита попарно объединяются в новые символы, начиная с символов, имеющих наименьшую вероятность, а затем, с учетом вероятностей вновь образованных символов, опять производят попарное объединение символов с наименьшими вероятностями и таким образом строят двоичное кодовое дерево, в вершине которого стоит символ с вероятностью 1.
П ример.
Построить методом Хаффмена оптимальный код для алфавита со следующим распределением вероятностей появления букв в тексте: A = 0,5; B = 0,15; C = 0,12; D = 0,1;
E =0,04; F = 0,04; G = 0,03;
H = 0,02.
Решение.
Сначала находят буквы с наименьшими вероятностями 0,02 (H) и 0,03 (G), затем проводят от них линию к точке, в которой вероятность появления буквы G равна 0,05. Затем берут две наименьшие вероятности 0,04 (F) и 0,04 (E) и получают новую точку с вероятностью 0,08.
Теперь наименьшими вероятностями обладают точки, соответствующие вспомогательным символам с вероятностями 0,05 и 0,08. Соединяем их линией с новой точкой, соответствующей вспомогательному символу с вероятностью 0,13.
Продолжаем алгоритм до тех пор, пока линия от основных и вспомогательных символов не сольются в точке, дающую суммарную вероятность, равную 1.
Обозначим каждую верхнюю линию (см. рисунок 2.1.1) цифрой 1, а нижнюю - цифрой 0. Получим ОНК, который для каждого слова представляет собой последовательность нулей и единиц, которые встречаются по пути к данному слову от конечной точки (1,00).
Полученные коды представлены в таблице 2.1.3.
Таблица 2.1.3 – Двоичный код Хаффмена для восьми сообщений
Буква | Вероятность | ОНК | Число знаков в кодовом слове | pili |
A B C D E F G H | 0,50 0,15 0,12 0,10 0,04 0,04 0,03 0,02 | 1 0 0 1 0 1 1 0 1 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 | 1 3 3 3 5 5 5 5 | 0,50 0,45 0,36 0,30 0,20 0,20 0,15 0,10 |
Пример.
Построить код Хаффмена для передачи сообщений при помощи трех частот f1, f2, f3, если символы первичного алфавита встречаются в сообщениях со следующими вероятностями: А = 0,24; Б = 0,18; В = 0,38;
Г = 0,1; Д = 0,06; Е = 0,02; Ж = 0,02.
Решение.
Таблица 2.1.4 – Троичный код Хаффмена для семи сообщений
Буква | Вероятность | Дерево | Код |
В А Б Г Д Е Ж | 0,38 0,24 0,18 0,1 0,06 0,02 0,02 |
| f1 f2 f3f1 f3f2 f3f3f1 f3f3f2 f3f3f3 |
Полученный код легко декодируется, так как ни один код не начинается с f1 и f2, кроме одного одноразрядного кода.
Алгоритм 2.1.1 – Алгоритм построения оптимального кода – рекурсивная процедура Huffman
Вход : n – количество букв, Р : array [1..n] of real - массив вероятностей появления букв в сообщении, упорядоченный по убыванию; 1 Р [1] … Р [n] > 0, Р [1] + … + Р [n] = 1.
Выход : С : array [1..n, 1..L] of 0..1 - массив элементарных кодов.
l : array [1..n] of 1..L – массив длин элементарных кодов схемы префиксного кодирования.
if n = 2 then
C [1, 1] : = 0; l [1] : = 1 {первый элемент}
C [2, 1] : = 1; l [2] : = 1 {второй элемент}
else
q : = P [n – 1] + P [n] {сумма двух последних вероятностей}
j : = Up (n, q ) {поиск места и вставка суммы}
Huffman (P, n – 1) {рекурсивный вызов}
Down (n, j) {достраивание кодов}
end if
Примечание. Функция Up находит место в массиве Р, в котором должно находиться число q и вставляет это число, сдвигая вниз остальные элементы. Процедура Down строит оптимальный код для n букв на основе построенного оптимального кода для n – 1 буквы. Для этого код буквы с номером j временно исключается из массива С путем сдвига вверх кодов букв с номерами, большими j, а затем в конец обрабатываемой части массива С добавляется мара кодов, полученных из кода буквы с номером j удлинением на 0 и 1, соответственно.
Для пары букв при любом распределении вероятностей оптимальное кодирование очевидно: первой букве нужно назначить код 0, а второй – 1. Именно это и делается в первой части оператора if основной процедуры Huffman. С помощью функции Up в исходном упорядоченном массиве Р отбрасываются две последние (наименьшие) вероятности, и их сумма вставляется в масси Р, так чтобы массив (на единицу меньшей длины) остался упорядоченным. При этом место вставки сохраняется в локальной переменной j. Так происходит до тех пор, пока не останется массив из двух элементов, для которого оптимальный код известен. После этого в обратном порядке строятся оптимальные коды для трех, четырех и т.д. элементов. При этом масси вероятностей Р уже не нужен – нужна только последовательсноть номеров кодов, которые должны быть изъяты из массива кодов и продублированы в конце с добавлением рахряда. А эта последовательность хранится в экземплярах локальной переменной j, соответствующих рекурсивным вызовампроцедуры Huffman.
Данный алгоритм можно использовать для сжатия файлов. Причем, если учитывать все 256 ASCII символов, то разницы в сжатии, например, *.txt и *.exe не будет.
К недостаткам алгоритма относятся:
-
Необходимость при кодировании двукратного прочтения файла первый раз для подсчета частоты вхождения символов,
второй – непостредственно для кодирования.
-
Необходимость хранения вместе с сжатым файлом декодирующего дерева для возможности восстановления файла.
- Введение
- Элементы теории чисел
- Модулярная арифметика
- Алгоритм Евклида для нахождения наибольшего общего делителя
- Вычисление обратных величин
- Основные способы нахождения обратных величин
- Расширенный алгоритм Евклида
- Китайская теорема об остатках
- Квадратичные вычеты
- Вычисления в конечных полях
- Свойства многочленов в двоичном поле gf(2)
- Достоинства вычислений в поле Галуа gf(2 n)
- Кодирование
- Оптимальное кодирование
- Обнаружение и исправление ошибок
- Общие понятия
- Линейные групповые коды
- Код Хэмминга
- Циклические коды
- Построение и декодирование конкретных циклических кодов
- Циклические коды, исправляющие две и большее количество ошибок, d0 5
- Сжатие информации
- Исключение повторения строк в последующих строках
- Алгоритм lzw
- Задания для самостоятельного выполнения
- Расчетно-графическая работа №1
- Расчетно-графическая работа №2
- Список рекомендуемой литературы
- Рекомендованная литература