Изменения

Перейти к: навигация, поиск
Нет описания правки
== Простое решение ==
Заметим, что <tex>\forall i: |c_i| \le leqslant n</tex>. Дополним все коды до длины <tex> n </tex> нулями с конца и запишем их друг за другом. Также необходимо передать <tex> n </tex>. При условии, что <tex> n </tex> не превышает <tex> 2^{32} - 1 </tex> получаем <tex> 32 + n^2 </tex> дополнительных бит на передачу префиксного кода.
Чтобы декодировать полученную информацию о коде, достаточно сначала узнать <tex>n</tex> и записать в префиксное дерево коды всех символов. Построив соответствующее дерево, можно заметить, что некоторые вершины являются единственным ребенком — такие вершины получены в результате дополнения нашего оптимального кода до <tex>n</tex> бит нулями. Все такие вершины можно просто удалить из дерева, и мы получим оптимальный префиксный код, который мы передавали.
Докажем, что код который мы получили совпадает с изначальным. В результате дополнения всех кодов до длины <tex>n</tex> мы, очевидно, ничего не потеряли в структуре дерева, ведь дополнение кода нулями фактически равносильно добавлению к дереву пустых (не несущих информации) листьев и вершин. В результате удаления вершин, являющихся единственным ребенком, мы также не удалим лишние: предположим мы удалили вершину, в которой содержался какой-то код, тогда она не могла быть единственным ребенком ввиду самого алгоритма Хаффмана, ведь мы выбираем 2 два узла с наименьшим весом и добавляем их к вновь сформированному узлу.
=== Пример ===
== Эффективное решение ==
Построим префиксное дерево, соответствующее нашему коду <tex>c</tex>. Наша задача состоит из двух подзадач: передача структуры этого дерева и передача информации для различения листьев, по которой впоследствии можно будет понять, где какой лист находится.
=== Передача структуры дерева ===
Обойдем дерево, используя [[Обход в глубину, цвета вершин|обход в глубину]], причем будем сначала всегда спускаться в левого ребенка, а только потом — в правого. Каждый раз, проходя по ребру запишем одну из букв <tex> L </tex>, <tex> R </tex> или <tex> U </tex>, в зависимости от того, куда по ребру мы прошли (<tex>L</tex> — в левого ребенка, <tex>R</tex> — в правого ребенка, <tex>U</tex> — в родителя). Эта информация поможет нам восстановить дерево.
Построим обход дерева Хаффмана для слова "миссисипи":
|}
Оценим используемое количество памяти. Так как в нашем дереве <tex> n </tex> листьев, то в нем <tex> 2 \cdot n - 2 </tex> ребер (это легко показать из алгоритма Хаффмана, в нем <tex> n - 1 </tex> итерация и на каждой в дерево добавляется по 2 два ребра), а символов в нашей записи будет <tex> 2 \cdot n - 1 </tex>, так как на каждое ребро приходится по символу плюс последний, терминальный, <tex> U </tex>.
=== Передача информации для восстановления листьев ===
=== Используемая память ===
В этом решении нам также придется передавать размер алфавита (<tex>32 </tex> бита).
Итого, задача решена с использованием <tex>n \lceil \log_2 \rceil n + 2n - 1 + 32 = n \lceil \log_2 \rceil n + 2n + 31 </tex> бит.
alphabet[следующий номер c'].push(code)
== Ссылки =Смотрите также === *[[Алгоритм_Хаффмана_за_O(n) | Алгоритм Хаффмана за O(n)]] == Источники информации == *[http://answerstop.org/question/127217/efficient-way-of-storing-huffman-tree Answerstop.org — Efficient way of storing Huffman tree]*[http://hashcode.ru/questions/283569/алгоритм-как-хранить-дерево-хаффмана Hashcode.ru — Как хранить дерево Хаффмана?]
*[[Алгоритм Хаффмана]]
*[[Обход в глубину, цвета вершин|Обход в глубину]]
[[Категория: Дискретная математика и алгоритмы]]
[[Категория: Алгоритмы сжатия ]]
32
правки

Навигация