Добавлен: 22.04.2023
Просмотров: 70
Скачиваний: 1
СОДЕРЖАНИЕ
1. Теоретические основы кодирования информации
1.1 Основы и основные понятия кодирования информации
1.2 Классификация назначения и способы представления кодов
1.3 Метод кодирования Хаффмана
2. Программная реализация алгоритма кодирования Хаффмана
2.1 Описание процесса реализации алгоритма кодирования Хаффмана
Мы по-прежнему будем рассматривать двоичные коды; обобщение полученных в этом случае результатов на коды с использованием произвольного числа m элементарных сигналов, как всегда, чрезвычайно просто. Начнем с простейшего случая кодов, которые соответствуют отдельной кодовой метке - последовательность цифр 0 и 1 - каждой «букве» сообщения. Каждый двоичный код для n-буквенного алфавита может быть связан с каким-то методом угадывания определенного перечислимого числа x, не превышающего n, с помощью вопросов, на которые отвечают только «да» или «нет» (0), что приводит нас к бинарный код. Учитывая вероятности p1, p2, ..., pn отдельных букв, передача многобуквенного сообщения будет наиболее экономичным кодом, для которого для этих вероятностей n значений x среднее значение числа вопросов (двоичное цифры: 0 и 1 или элементарные сигналы) является наименьшим.
Прежде всего, среднее число двоичных элементарных сигналов в закодированном сообщении на букву исходного сообщения не может быть меньше, чем H, где H = - p1 log p1 - p2 log p2 - ... - pn log pn - энтропия из эксперимента, состоящего в распознавании одной буквы текста (или, короче говоря, просто энтропии одной буквы). Из этого следует, что при любом способе кодирования для записи длинного сообщения из M букв требуется не менее двоичных цифр MN и не может превышать один бит.
Если вероятности p1, p2, ..., pn не все равны друг другу, то H <log n; поэтому естественно думать, что учет статистических закономерностей сообщения может позволить построить код более экономичным, чем лучший унифицированный код, требующий минимум M log n двоичных цифр для ввода текста из M букв.
1.2 Классификация назначения и способы представления кодов
Коды можно классифицировать по различным критериям:
1. На основе (количество символов в алфавите): двоичный (двоичный m = 2), а не двоичный (m № 2).
2. Длина кодовых комбинаций (слов): равномерная, если все кодовые комбинации имеют одинаковую длину и не равны, если длина кодовой комбинации не является постоянной.
3. Методами передачи: последовательный и параллельный; block - данные сначала помещаются в буфер, а затем передаются на канал и бинарные непрерывные.
4. По помехоустойчивости: простой (примитивный, полный) - все возможные комбинации кода (без избыточности) используются для передачи информации; Корректирующее (заклинивание) - не все, но только часть (разрешенных) кодовых комбинаций используется для передачи сообщений.
5. В зависимости от цели и применения условно могут быть выделены следующие типы кодов:
Внутренние коды - это коды, используемые внутри устройств. Это машинные коды, а также коды, основанные на использовании систем позиционных номеров (двоичные, десятичные, двоично-десятичные, восьмеричные, шестнадцатеричные и т. Д.). Наиболее распространенным кодом на компьютере является двоичный код, который позволяет вам просто реализовать аппаратное устройство для хранения, обработки и передачи данных в двоичном коде. Он обеспечивает высокую надежность устройств и простоту операций с данными в двоичном коде. Двоичные данные, объединенные в группы из 4, образуют шестнадцатеричный код, который хорошо согласуется с архитектурой компьютера, работающего с этими несколькими байтами (8 бит).
Коды для обмена данными и их передачи по каналам связи. Широкое распространение в ПК получил код ASCII (American Standard Code for Information Interchange). ASCII - это 7-битный код буквенно-цифровых и других символов. Поскольку ЭВМ работают с байтами, то 8-й разряд используется для синхронизации или проверки на четность, или расширения кода. В ЭВМ фирмы IBM используется расширенный двоично-десятичный код для обмена информацией EBCDIC (Extended Binary Coded Decimal Interchange Code). В каналах связи широко используется телетайпный код МККТТ (международный консультативный комитет по телефонии и телеграфии) и его модификации (МТК и др.).
При кодировании информации для передачи по каналам связи, в том числе внутри аппаратным трактам, используются коды, обеспечивающие максимальную скорость передачи информации, за счет ее сжатия и устранения избыточности (например: коды Хаффмана и Шеннона-Фано), и коды обеспечивающие достоверность передачи данных, за счет введения избыточности в передаваемые сообщения (например: групповые коды, Хэмминга, циклические и их разновидности).
Коды для специальных применений - это коды, предназначенные для решения специальных задач передачи и обработки данных. Примерами таких кодов является циклический код Грея, который широко используется в АЦП угловых и линейных перемещений. Коды Фибоначчи используются для построения быстродействующих и помехоустойчивых АЦП.
В зависимости от применяемых методов кодирования, используют различные математические модели кодов, при этом наиболее часто применяется представление кодов в виде: кодовых матриц; кодовых деревьев; многочленов; геометрических фигур и т.д. Рассмотрим основные способы представления кодов.
Матричное представление кодов. Используется для представления равномерных n - значных кодов. Для примитивного (полного и равномерного) кода матрица содержит n - столбцов и 2n - строк, т.е. код использует все сочетания. Для помехоустойчивых (корректирующих, обнаруживающих и исправляющих ошибки) матрица содержит n - столбцов (n = k+m, где k-число информационных, а m - число проверочных разрядов) и 2k - строк (где 2k - число разрешенных кодовых комбинаций). При больших значениях n и k матрица будет слишком громоздкой, при этом код записывается в сокращенном виде. Матричное представление кодов используется, например, в линейных групповых кодах, кодах Хэмминга и т.д.
Представление кодов в виде кодовых деревьев. Кодовое дерево - связной граф, не содержащий циклов. Связной граф - граф, в котором для любой пары вершин существует путь, соединяющий эти вершины. Граф состоит из узлов (вершин) и ребер (ветвей), соединяющих узлы, расположенные на разных уровнях. Для построения дерева равномерного двоичного кода выбирают вершину называемую корнем дерева (истоком) и из нее проводят ребра в следующие две вершины и т.д.
1.3 Метод кодирования Хаффмана
Метод кодирования или сжатия информации на основе двоичных кодирующих деревьев был предложен Д.А. Хаффманом в 1952 году задолго до появления современного цифрового компьютера. Обладая высокой эффективностью, он и его многочисленные адаптивные версии лежат в основе многих методов, используемых в современных алгоритмах кодирования. Код Хаффмана редко используется отдельно, чаще работая в связке с другими алгоритмами кодирования. Метод Хаффмана является примером построения кодов переменной длины, имеющих минимальную среднюю длину. Этот метод производит идеальное сжатие, то есть сжимает данные до их энтропии, если вероятности символов точно равны отрицательным степеням числа 2.
Этот метод кодирования состоит из двух основных этапов:
- Построение оптимального кодового дерева.
- Построение отображения код-символ на основе построенного дерева.
Алгоритм основан на том, что некоторые символы из стандартного 256-символьного набора в произвольном тексте могут встречаться чаще среднего периода повтора, а другие - реже. Следовательно, если для записи распространенных символов использовать короткие последовательности бит, длиной меньше 8, а для записи редких символов - длинные, то суммарный объем файла уменьшится. В результате получается систематизация данных в виде дерева («двоичное дерево»).
Пусть A={a1,a2,...,an} - алфавит из n различных символов, W={w1,w2,...,wn} - соответствующий ему набор положительных целых весов. Тогда набор бинарных кодов C={c1,c2,...,cn}, такой что:
- ci не является префиксом для cj, при i!=j; минимальна (|ci| длина кода ci) называется минимально-избыточным префиксным кодом или иначе кодом Хаффмана.
Бинарным деревом называется ориентированное дерево, полустепень исхода любой из вершин которого не превышает двух.
Вершина бинарного дерева, полустепень захода которой равна нулю, называется корнем. Для остальных вершин дерева полустепень захода равна единице.
Пусть Т- бинарное дерево, А=(0,1)- двоичный алфавит и каждому ребру Т-дерева приписана одна из букв алфавита таким образом, что все ребра, исходящие из одной вершины, помечены различными буквами. Тогда любому листу Т-дерева можно приписать уникальное кодовое слово, образованное из букв, которыми помечены ребра, встречающиеся при движении от корня к соответствующему листу. Особенность описанного способа кодирования в том, что полученные коды являются префиксными.
Очевидно, что стоимость хранения информации, закодированной при помощи Т-дерева, равна сумме длин путей из корня к каждому листу дерева, взвешенных частотой соответствующего кодового слова или длиной взвешенных путей: , где - частота кодового слова длины во входном потоке. Рассмотрим в качестве примера кодировку символов в стандарте ASCII. Здесь каждый символ представляет собой кодовое слово фиксированной(8 бит) длины, поэтому стоимость хранения определится выражением , где W- количество кодовых слов во входном потоке.
Поэтому стоимость хранения 39 кодовых слов в кодировке ASCII равна 312, независимо от относительной частоты отдельных символов в этом потоке. Алгоритм Хаффмана позволяет уменьшить стоимость хранения потока кодовых слов путем такого подбора длин кодовых слов, который минимизирует длину взвешенных путей. Будем называть дерево с минимальной длиной путей деревом Хаффмана.
Классический алгоритм Хаффмана на входе получает таблицу частот встречаемости символов в сообщении. Далее на основании этой таблицы строится дерево кодирования Хаффмана (Н-дерево).
1. Символы входного алфавита образуют список свободных узлов. Каждый лист имеет вес, который может быть равен либо вероятности, либо количеству вхождений символа в сжимаемое сообщение;
2. Выбираются два свободных узла дерева с наименьшими весами;
Создается их родитель с весом, равным их суммарному весу;
Родитель добавляется в список свободных узлов, а два его потомка удаляются из этого списка;
Одной дуге, выходящей из родителя, ставится в соответствие бит 1, другой - бит 0;
Шаги, начиная со второго, повторяются до тех пор, пока в списке свободных узлов не останется только один свободный узел. Он и будет считаться корнем дерева.
Допустим, у нас есть следующая таблица частот.
Табл. 1
15 |
7 |
6 |
6 |
5 |
А |
Б |
В |
Г |
Д |
На первом шаге из листьев дерева выбираются два с наименьшими весами - Г и Д. Они присоединяются к новому узлу- родителю, вес которого устанавливается 5+6= 11. Затем узлы Г и Д удаляются из списка свободных. Узел Г соответствует ветви 0 родителя, узел Д - ветви 1.
На следующем шаге то же происходит с узлами Б и В, так как теперь эта пара имеет самый меньший вес в дереве. Создается новый узел с весом 13, а узлы Б и В удаляются из списка свободных.
На следующем шаге «наилегчайшей» парой оказываются узлы Б/В и Г/Д.
Для них еще раз создается родитель, теперь уже с весом 24. Узел Б/В соответствует ветви 0 родителя, Г/Д - ветви 1.
На последнем шаге в списке свободных осталось только 2 узла - это узел А и узел Б (Б/В)/(Г/Д). В очередной раз создается родитель с весом 39, и бывшие свободные узлы присоединяются к разным его ветвям.
Поскольку свободным остался только один узел, то алгоритм построения дерева кодирования Хаффмана завершается.
Каждый символ, входящий в сообщение, определяется как конкатенация нулей и единиц, сопоставленных ребрам дерева Хаффмана, на пути от корня к соответствующему листу.
Для данной таблицы символов коды Хаффмана будут выглядеть, как показано в табл. 2.
Табл. 2. Коды Хаффмана
А |
01 |
Б |
100 |
В |
101 |
Г |
110 |
Д |
111 |
Наиболее частый символ сообщения А закодирован наименьшим количеством бит, а наиболее редкий символ Д - наибольшим. Стоимость хранения кодированного потока, определенная как сумма длин взвешенных путей, определится выражением 15*1+7*3+6*3+6*3+5*3=87, что существенно меньше стоимости хранения входного потока (312).
Поскольку ни один из полученных кодов не является префиксом другого, они могут быть однозначно декодированы при чтении их из потока.
Алгоритм декодирования предполагает просмотр потоков битов и синхронное перемещение от корня вниз по дереву Хаффмана в соответствии со считанным значением до тех пор, пока не будет достигнут лист, то есть декодировано очередное кодовое слово, после чего распознавание следующего слова вновь начинается с вершины дерева.
Классический алгоритм Хаффмана имеет один существенный недостаток. Для восстановления содержимого сжатого сообщения декодер должен знать таблицу частот, которой пользовался кодер. Следовательно, длина сжатого сообщения увеличивается на длину таблицы частот, которая должна посылаться впереди данных, что может свести на нет все усилия по сжатию сообщения. Кроме того, необходимость наличия полной частотной статистики перед началом собственно кодирования требует двух проходов по сообщению: одного для построения модели сообщения (таблицы частот и дерева Хаффмана), другого собственно для кодирования.