ВЕСТНИК САНКТ-ПЕТЕРБУРГСКОГО УНИВЕРСИТЕТА
Сер. 10. 2010. Вып. 3
УДК 519.688 М. А. Герасимов
РЕАЛИЗАЦИЯ АЛГОРИТМА ХАФФМАНА
С ЗАДАННОЙ ДЛИНОЙ РАЗБИЕНИЙ ВХОДНОГО ПОТОКА
НА МАШИНАХ ТЬЮРИНГА С ПОЧТИ ЛИНЕЙНЫМ ВРЕМЕНЕМ
Введение. В монографии [1] рассматривается алгоритм оптимального кодирования конечного набора символов в алфавите, содержащем меньше букв, чем заданный набор символов. Изложенный метод, применяемый к битовой последовательности входных данных, разделяемой на разбиения фиксированной длины, позволяет эффективно сжимать исходные данные [2]. Выбор длины разбиения определяет количество символов во входном алфавите. Метод широко применяется в сложных алгоритмах упаковки/распаковки данных различных вычислительных устройств [3].
Для оценки времени работы алгоритма рассматривается одноленточная детерминированная машина Тьюринга со входной и выходной лентами [4, с. 148-184]. Время ее работы оценивается как число шагов в зависимости от длины входных данных.
Доказано, что при выборе длины разбиения (битового представления входного алфавита) т = \_j: log nj +1, где п - общая длина входных данных, время работы алгоритма Хаффмана может быть сделано «почти линейным», более точно, с верхней оценкой 0(птг) при любом рациональном к ^ 2, logn ^ к, п ^ 4.
В статье рассматривается приложение алгоритма Хаффмана к решению NP - полной задачи о разбиении множества положительных целых чисел. Предлагается специальный метод сведения данной задачи к задаче кодирования разбиения оптимальным кодом. Описан специальный случай задачи о разбиении, когда время ее решения на детерминированной машине Тьюринга с одной рабочей лентой может быть сделано «почти линейным».
Детерминированная машина Тьюринга. В качестве модели вычисления рассмотрим детерминированные машины Тьюринга с конечным множеством состояний Q = {qi, ■■■,4n}. Предположим, что входные данные записаны на входной ленте, обрабатываются на рабочей ленте и результат записывается на выходной ленте.
При работе машины Тьюринга используем алфавит, состоящий из четырех символов {#,b,0,1}. Этот алфавит применяется для всех трех лент машины Тьюринга: входной, выходной и рабочей. Результатом работы алгоритма считаются битовая последовательность, кодирующая исходные данные, и соответствующее дерево кодирования (представленное в виде набора длин кодирующих цепочек), позволяющее однозначно восстановить исходную последовательность. Будем считать, что кодирующая входные данные цепочка битов отделяется от кода длин дерева Хаффмана символом ’#’. Далее
Герасимов Михаил Александрович — кандидат физико-математических наук, доцент кафедры информатики математико-механического факультета Санкт-Петербургского государственного университета. Количество опубликованных работ: 12. Научные направления: сложность вычислений, теория кодирования, теория алгоритмов. E-mail: [email protected].
© М. А. Герасимов, 2010
длины кодирующих цепочек также отделяются друг от друга символом ’ # ’. При этом предполагаем, что процесс восстановления присходит в два этапа: восстанавливается сначала декодирующее дерево, а затем закодированная битовая последовательность.
Входные данные записаны в виде битовой последовательности на входной ленте между двумя маркерами ’ # ’. Считывание второго маркера означает конец цепочки входных данных. Входная лента позволяет считывать входные данные произвольное количество раз.
На выходной ленте можно только записывать результат вычисления в виде последовательности символов рабочего алфавита. Кроме преобразованной входной последовательности символов, результат вычисления содержит код кодирующего дерева, восстанавливающий исходную входную битовую последовательность. Для оптимизации выводимой битовой последовательности этот код содержит лишь длины кодирующих цепочек [5]. Каждый символ выходной цепочки записывается лишь один раз и больше не изменяется.
Код Хаффмана. Сжатие Хаффмана - статистический метод сжатия, который может уменьшать среднюю длину кодового слова для символов конечного алфавита [1]. Первоначально код Хаффмана применялся для оптимизации кодирования символов большего по мощности алфавита символами меньшего по мощности алфавита. Код Хаффмана является примером кода, оптимального в случае, когда все вероятности появления символов в сообщении - целые отрицательные степени двойки. В остальных случаях код Хаффмана дает хорошее приближение к оптимальному коду и применяется во многих алгоритмах сжатия информации [6, с. 72-95]. Особенность этого алгоритма - необходимость двух проходов для сжимаемого набора данных. В прикладных системах чаще всего используют адаптированный алгоритм Хаффмана, который дает меньший коэффициент сжатия, однако требует лишь одного прохода для своего завершения [7].
Далее используем классический подход к построению кодирующего дерева, т. е. предположим, что метод содержит два этапа построения: составление частотной таблицы и собственно построение дерева на основе полученных частот. Для анализа временной сложности алгоритма будем считать, что результатом работы машины Тьюринга будет не только выходная кодирующая последовательность, но и представление длины входных данных в виде битовой цепочки. Кроме того, будем предполагать, что в выходную последовательность записывается набор длин цепочек кодов, позволяющий однозначно восстановить кодирующее дерево алгоритма Хаффмана [5]. Следует отметить, что длина h кодирующей битовой последовательности, ввиду оптимальности алгоритма Хаффмана, не превосходит n - длины входной битовой последовательности. Длина битового представления n не больше, чем [logn\, а представление набора длин кодов (ввиду наличия разделяющих маркеров) не больше, чем
м
[logli i,
i=1
где li - длина г-го кода алгоритма Хаффмана. Поскольку все li положительны и больше или равны 1, то справедливы соотношения
мм У~] [log li\ <^2 li = h < n.
i=1 i=1
Таким образом, длина результирующих данных алгоритма оценивается как O(n).
Сам код Хаффмана может быть построен по следующему алгоритму:
1) выписываются в ряд все символы алфавита в порядке убывания вероятности их появления в тексте;
2) последовательно объединяются два символа с наименьшими вероятностями появления в новый составной символ, вероятность возникновения которого полагается равной сумме вероятностей составляющих его символов;
3) строится дерево, каждый внутренний узел которого имеет суммарную вероятность всех узлов, находящихся ниже него;
4) прослеживается путь к каждому листу дерева и помечается направление к каждому узлу (направо - 1, налево - 0) и строится кодовое слово для данного символа.
Далее вместо символов некоторого алфавита A будут рассматриваться битовые цепочки алфавита A = {0,1} заданной фиксированной длины. Поскольку все они различны, их всегда можно отождествить с символами некоторого алфавита мощности 2m, где m - длина каждой битовой цепочки. Рассматриваемая реализация алгоритма Хаффмана использует данный линейный список входных разбиений с их частотными характеристиками в качестве исходных символов входного алфавита и дерево частотного кодирования этого алфавита префиксными кодами.
Предположим, что поступающий входной поток битов разбивается на указанные отдельные блоки (разбиения) фиксированной длины. Таким образом, при разбиении потока на блоки по m битов, входной алфавит содержит не более чем 2m символов. Если n не кратно m, последнее разбиение может быть дополнено нулями до длины m. При восстановлении исходного потока эти нули могут быть отброшены, поскольку известна величина n, которая добавляется к выходным данным машины Тьюринга.
Оценка времени работы алгоритма.
Теорема 1. Каково бы не было рациональное k, log n ^ k ^ 2, алгоритм Хаффмана, кодирующий входной битовый поток неравномерным кодом в двоичном алфавите A = {0,1}, может быть реализован на детерминированной машине Тьюринга с временной сложностью
, k + 1 ,
0(п к ).
Доказательство. Будем считать, что размер списка входных разбиений при ограничениях на длину одного разбиения то = lognj + 1, где п - длина входной цепочки данных. В этом случае бинарный входной поток данных разбивается на не
более чем
разбиений, которые можно считать символами входного алфа-
Ulog nJ+1
вита. Заметим, что для любого 2 ^ k ^ log n, n ^ 4, общее число различных разбиений не превосходит а при длине то = lognj + 1 максимальное количе-
|_11°8 п\+1
ство разных разбиений в частотной таблице не превосходит 2 у/п.
Рассмотрим худший случай для оценки размера таблицы. В соответствии с работой Шеннона [9] максимальная энтропия (как мера среднего времени обработки одного разбиения) дискретного ансамбля (составляемого разными входными разбиениями) максимальна в случае равных частот повторения разбиений во входном потоке. В таком случае достигается максимальный размер таблицы частот и максимальное время обработки входного потока. При этом каждое разбиение встречается во входном потоке не более
П
[llog nj+l
kn
<
2 y/n log n yfn
раз. Общая длина двоичной записи частоты повторения разбиения в данном случае не превосходит
k — 1
-----log п — log log п + log к.
k
Учитывая общее количество разных разбиений в частотной таблице, получаем, что общий ее размер не превосходит
к — 1
2 у/п{----logn — log log п + log к).
k
Таким образом, увеличение счетчика частоты повторения для одного разбиения во входном потоке потребует совершить не более 2 у/п{ log п — log log n + log к) шагов
машины Тьюринга, что дает общую оценку времени заполнения частотной таблицы
4кп к — 1 1,ч
i---Vn(—;— logn — log logn + log к).
log n k
Отсюда следует, что частотная таблица может быть заполнена не более чем за 4(k — 1)пт шагов машины Тьюринга. Поскольку рассматривался худший случай для частотной таблицы, в общем случае эта оценка продолжает оставаться верной. Построение кодирующего дерева по заданной частотной таблице требует не более чем |~2{/п~| итераций алгоритма Хаффмана, поскольку каждая итерация уменьшает количество элементов частотной таблицы на единицу. Каждая итерация включает в себя удаление двух текущих элементов с наименьшими значениями частоты и построение нового элемента, соответствующего суммарному значению частот удаленных элементов. Итерация завершается вставкой полученного элемента таким образом, чтобы сами элементы были отсортированы по убыванию. Поиск места для вставки элемента реализуется не более чем за O(yfn) шагов. Сама вставка также может быть реализована не более чем за O(yfn) шагов детерминированной машины Тьюринга. Поскольку к ^ 2, итоговую сложность этого этапа можно оценить величиной 0{у/п * [2у/п\) = 0(п). Следовательно, все итерации алгоритма Хаффмана, выполняемые при построении кодового дерева, реализуются не более чем за O(n) шагов. Вывод результатов алгоритма Хаффмана в данном случае может быть сделан также не более чем за O(n) шагов машины Тьюринга. Таким образом, наиболее сложная по числу шагов на машине Тьюринга часть алгоритма - построение частотной таблицы - дает верхнюю оценку временной сложности алгоритма Хаффмана в 0(п^) шагов машины Тьюринга, где logn ^ к ^ 2. Теорема доказана.
Как видно из предложенного доказательства, с одной стороны, время работы при заполнении частотной таблицы ограничено функцией Т(п) = А{к — 1 )п_е_, т. е. степень n стремится к 1 при k ^ ж, но при этом возрастает линейный коэффициент. Таким образом, при n ^ 10 000 рекомендуется полагать k = 2, при n ^ 1 000 000 следует использовать алгоритм при k = [log n\.
Важный частный случай задачи разбиения множества. Рассмотрим задачу
о разбиении множества целых чисел на два равных по весу подмножества в следующем виде. Пусть дано множество X = {x\, ..,хм} натуральных чисел. Предположим,
что Уг ^ 1,ж* > 0. Требуется найти два подмножества Si С X и S2 С X, такие, что X = Si U S2, Si f| S2 = 0,
xk = X ,
XkESi xj ES2
м
S = ^2 Xi,
i=1
S = ^2 xi +13 xj ■
XiESi Xj ES2
В рассматриваемом частном случае будем считать, что исходное множество - это множество относительных весов элементов множества X, т. е. рациональных чисел wi =
Конечная цель - та же, что и в стандартной задаче разбиения, с той разницей, что требуется разбить множество рациональных чисел. Отметим, что входные данные в этом случае - таблица относительных весов элементов. Понятно, что решение такой задачи дает и решение исходной задачи - классического разбиения множества. В случае относительных весов имеет место равенство
м
J2wi = 1 (1)
i=1
Ввиду указанного равенства, относительные веса элементов могут рассматриваться как вероятности соответствующих событий появления элементов в исходном множестве. Тогда можно применить рассмотренный алгоритм Хаффмана [1], кодирующий исходные элементы цепочками, длины которых обратно пропорциональны их вероятностям появления. Отличие от предыдущего применения заключается в том, что подсчитывать частоты появления разбиений нет необходимости, вместо них используются относительные веса исходных элементов. В этом случае входными данными для машины Тьюринга будет набор целых чисел исходного множества, который потребует для своей записи на входной ленте не менее
м
n = Y^ l"log Xi 1 (2)
i=i
клеток машины Тьюринга. В соответствии с [8] данная формулировка задачи о разбиении является стандартной, поэтому в дальнейшем снова будем считать, что n, определяемое формулой (2), - длина входных данных.
Теорема 2. Пусть входной поток данных содержит X = {х1,х2, ...,хм} различных битовых разбиений. Относительная частота каждого разбиения xi G X ранена wi = 2~mi, где mi ^ 1, mi - целое. Тогда дерево кодирования данных разбиений алгоритмом Хаффмана является деревом кодирования этих же разбиений методом Шеннона-Фано [9, 10].
Доказательство. Рассмотрим дерево кодирования Хаффмана. Согласно работе [1], при его построении будет соблюдаться следующий инвариант: на каждом шаге построения последний и предпоследний элементы в отсортированном списке имеют равный относительный вес. Это выполняется, в том числе и на последнем шаге построения дерева Хаффмана, когда множество имеет всего два элемента. Но в таком случае дерево Хаффмана является деревом Шеннона-Фано, так как веса левого и правого поддеревьев равны. Теорема доказана.
Следствие. Поскольку дерево кодирования методом Шеннона-Фано дает решение задачи о разбиении множества {х1,х2, ...,хм} на два подмножества с одинаковыми весами, то в случае, когда относительные веса элементов {w1,w2,...,wM} разбиваемого множества равны 2-mi, г ^ 1, для некоторых целых mi ^ 1, задача о разбиении может быть решена за почти линейное время, точнее, с временной сложностью O(nlog(n)) шагов детерминированной машины Тьюринга, где n - длина бинарного представления входных данных. Поскольку класс алгоритмов O(nlog(n)) содержится в 0(п~ь~), для любого к ^ 2, данный алгоритм можно назвать почти линейным.
Доказательство. Предлагается следующий почти линейный алгоритм решения задачи о разбиении. Исходные натуральные числа, записанные в двоичном представлении, располагаются на входной ленте машины Тьюринга. Сортируем исходное множество натуральных чисел в порядке их убывания. Это можно сделать за O(nlog(n)) шагов детерминированной машины Тьюринга [11, с. 47-69]. Далее, согласно [12, с. 274281], используя равенство (1), можно построить кодирующее дерево алгоритма Хаффмана не более чем за (n log n) шагов машины Тьюринга, где n - длина представления частотной таблицы. По теореме 2 в данном случае полученное кодовое дерево Хаффмана является деревом Шеннона-Фано, т. е. веса самых верхних левого и правого поддеревьев равны. Решение задачи разбиения может быть получено левосторонним обходом левого и правого поддеревьев. Это можно сделать не более чем за O(n) шагов рассматриваемой детерминированной машины Тьюринга. Следовательно, общая временная сложность решения задачи о разбиении в таком случае не превосходит O(n log n).
Литература
1. Huffman D. A. A method for construction of minimum redundancy codes // Proc. of IRE. 1952. Vol. 40. P. 1098-1101.
2. Chowdhury R. A. An Efficient Decoding Technique for Huffman Codes // Inform. Proc. Letter. 2002. Vol. 81, N 6. P. 305-308.
3. Milidiu R. L., Pessoa A. A., Laber E. S. Efficient implementation of the warm-up algorithm for the construction of length-restricted prefix codes // Proc. of ALENEX (Intern. Workshop on Algorithm Engineering and Experimentation). 1999. P. 1-17.
4. Минский М. Вычисления и автоматы / пер. c англ. Б. Л. Овсиевича, Л. Я. Розенблюма. М.: Мир, 1971. 364 с.
5. Schwartz E. S., Kallick B. Generating a canonical prefix encoding // Communications of the ACM. 1964. Vol. 7, N 3. P. 166-169.
6. Гэри M., Джонсон Д. Вычислительные машины и труднорешаемые задачи / пер. с англ. Е. В. Левнера, М. А. Фрумкина; под ред. А. А. Фридмана. М.: Мир, 1982. 416 c.
7. Кнут Д. Э. Искусство программирования: в 2 т. / пер. с англ.; под ред. Ю. В. Казаченко. 3-е изд. Т. 1: Основные алгоритмы. М.: Изд. дом «Вильямс», 2000. 822 c.
8. Bently J. L., Sleator D. D., Tarjan R. E., Wei V. K. A locally adaptive data compression algorithm // Communications of the ACM. 1986. Vol. 29, N 4. P. 320-330.
9. Shannon C. E. A Mathematical Theory of Communication // Bell System Technical Journal. 1948. Vol. 27, July. P. 379-423.
10. Fano R. M. The transmission of information: technical report. N 65. Cambridge (Mass.), USA: Research Laboratory of Electronics, M.I.T., 1949. 13 p.
11. Ахо А., Хопкрофт Дж., Ульман Дж. Построение и анализ вычислительных алгоритмов / пер. с англ. А. О. Слисенко; под ред. Ю. В. Матиясевича. М.: Мир, 1979. 536 c.
12. Кормен Т., Лейзерсон Ч., Ривест Р., Штайн К. Алгоритмы: построение и анализ. 2-е изд. / пер. с англ. К. Белова, Ю. Буравлева, Д. Ботина, В. Горелик; под ред. А. Шеня. М.: Изд. дом «Вильямс», 2007. 957 c.
Статья рекомендована к печати проф. А. Н. Тереховым.
Статья принята к печати 1 апреля 2010 г.