Код Хаффмана с длиной кодового слова не более L бит — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 9: Строка 9:
 
# Рассмотрим первый список (с монетами самого низкого номинала). Разобьем в нем все монеты на пары (1 и 2, 3 и 4 и т. д.) Заменим каждую пару монет одной новой монетой, номинал и вес которой равен сумме номиналов и весов старых. Если число монет было нечетно, то последнюю монету, которая не имеет пары, исключим из рассмотрения.
 
# Рассмотрим первый список (с монетами самого низкого номинала). Разобьем в нем все монеты на пары (1 и 2, 3 и 4 и т. д.) Заменим каждую пару монет одной новой монетой, номинал и вес которой равен сумме номиналов и весов старых. Если число монет было нечетно, то последнюю монету, которая не имеет пары, исключим из рассмотрения.
 
# Объединим первый список со вторым так, чтобы монеты в получившемся списке остались упорядочены по весу.
 
# Объединим первый список со вторым так, чтобы монеты в получившемся списке остались упорядочены по весу.
# Будем повторять шаги 2-3 до тех пор, пока у нас не останется один список. В нем будут содержаться монеты номиналом 1 (<tex>2^0</tex>), упорядоченные по весу. Возьмем первые <tex>S</tex> монет из списка. Это и будет ответ к задаче.
+
# Будем повторять шаги 2-3 до тех пор, пока у нас не останется один список, в котором содержатся монеты номинала 1 (<tex>2^0</tex>), упорядоченные по весу. Возьмем первые <tex>S</tex> монет из списка. Это и будет ответ к задаче.
  
 
== Сведение к генерации кода Хоффмана с длиной кодового слова не более L бит. ==
 
== Сведение к генерации кода Хоффмана с длиной кодового слова не более L бит. ==
Строка 35: Строка 35:
 
{| class="wikitable"
 
{| class="wikitable"
 
| Номинал = <tex> 2^{-2} </tex> ||  <tex>(2^{-2}; 1)</tex> || <tex>(2^{-2}; 2)</tex> || <tex>(2^{-2}; 3)</tex>
 
| Номинал = <tex> 2^{-2} </tex> ||  <tex>(2^{-2}; 1)</tex> || <tex>(2^{-2}; 2)</tex> || <tex>(2^{-2}; 3)</tex>
 +
|-
 +
| Номинал = <tex> 2^{-1} </tex> ||  <tex>(2^{-1}; 1)</tex> || <tex>(2^{-1}; 2)</tex> || <tex>(2^{-2}; 3)</tex>
 +
|}
 +
 +
Выполним объединение первого списка по парам и исключим последний элемент, т.к. для него нет пары:
 +
 +
| Номинал = <tex> 2^{-2} </tex> ||  <tex>(2^{-1}; 3)</tex> || ||
 
|-
 
|-
 
| Номинал = <tex> 2^{-1} </tex> ||  <tex>(2^{-1}; 1)</tex> || <tex>(2^{-1}; 2)</tex> || <tex>(2^{-2}; 3)</tex>
 
| Номинал = <tex> 2^{-1} </tex> ||  <tex>(2^{-1}; 1)</tex> || <tex>(2^{-1}; 2)</tex> || <tex>(2^{-2}; 3)</tex>
 
|}
 
|}

Версия 19:12, 17 декабря 2014

Код Хаффмана с длиной слова не более L бит - это вариация классического кода Хоффмана с дополнительным ограничением: длина каждого кодового слова не должна превышать заданной константы. Здесь будет приведен алгоритм, решающий эту задачу за время [math] O(nL) [/math], где [math]L[/math] - максимальная длина кодового слова, [math]n[/math] - размер алфавита, c помощью сведения задачи к одной из вариаций задачи о банкомате.

Задача о банкомате.

В вариации задаче о банкомате, которую мы рассмотрим, у вас имеется [math]N[/math] монет. Каждая монета характеризуется двумя параметрами: номиналом и весом. При этом все номиналы являются степенями двойки и не превышают [math]2^0[/math]. Необходимо выбрать из имеющихся монет некоторый набор так, чтобы их суммарный номинал был равен [math]S[/math] (натуральное число), а суммарный вес минимален.

Алгоритм решения задачи о банкомате.

Рассмотрим алгоритм решения приведенной выше вариации задачи о банкомате, считая, что решение существует.

  1. Разделим имеющиеся у нас монеты на списки по номиналу (свой список для каждого номинала) и упорядочим монеты по возрастанию весов внутри списков, а списки в порядке возрастания номиналов.
  2. Рассмотрим первый список (с монетами самого низкого номинала). Разобьем в нем все монеты на пары (1 и 2, 3 и 4 и т. д.) Заменим каждую пару монет одной новой монетой, номинал и вес которой равен сумме номиналов и весов старых. Если число монет было нечетно, то последнюю монету, которая не имеет пары, исключим из рассмотрения.
  3. Объединим первый список со вторым так, чтобы монеты в получившемся списке остались упорядочены по весу.
  4. Будем повторять шаги 2-3 до тех пор, пока у нас не останется один список, в котором содержатся монеты номинала 1 ([math]2^0[/math]), упорядоченные по весу. Возьмем первые [math]S[/math] монет из списка. Это и будет ответ к задаче.

Сведение к генерации кода Хоффмана с длиной кодового слова не более L бит.

Пусть [math]L[/math] - ограничение на длину кодового слова, а [math]P=\{p_{1},p_{2},...,p_{n}\}[/math] - частоты символов алфавита.

  1. Отсортируем символы алфавита в порядке возрастания их частот.
  2. Для каждого символа создадим [math]L[/math] монет номиналами [math]2^{-1}..2^{-L}, каждая из которых имеет вес \lt tex\gt p_{i}[/math].
  3. С помощью описанного выше алгоритма выберем набор монет суммарным номиналом [math]n - 1[/math] ([math]n[/math] - размер алфавита) с минимальным суммарным весом.
  4. Посчитаем массив [math]H=\{h_{1},h_{2},...,h_{n}\}[/math], где [math]h_{i}[/math] - количество монет номинала [math]p_{i}[/math], которые попали в наш набор.

При этом [math]h_{i}[/math] - это длина кодового слова для [math]i[/math]-го символа.Зная длины кодовых слов, легко восстановить и сам код.

Восстановление ответа.

  1. Отсортируем все символы по возрастанию длины кодового слова, которое им соответствует, а при равенстве длин - в алфавитном порядке.
  2. Первому символу сопоставим код, состоящий из нулей, соответствующей длины.
  3. Каждому следующему символу сопоставим следующее двоичное число. При этом если его длина меньше необходимой, то допишем нули справа.

Пример работы алгоритма генерации кода Хоффмана с длиной кодового слова не более L бит

Пусть [math]A=\{a_{1},a_{2},...,a_{n}\}[/math] — алфавит из n различных символов, [math]P=\{p_{1},p_{2},...,p_{n}\}[/math] — соответствующий ему набор положительных целых весов. Пусть [math]L = 2[/math] - ограничение на длину кодового слова.

Сначала создадим необходимый набор монет;

[math](2^{-1}; 1), (2^{-2}; 1), (2^{-1}; 2), (2^{-2}; 2), (2^{-1}; 3), (2^{-2}; 3)  [/math]

Распределим их по спискам:

Номинал = [math] 2^{-2} [/math] [math](2^{-2}; 1)[/math] [math](2^{-2}; 2)[/math] [math](2^{-2}; 3)[/math]
Номинал = [math] 2^{-1} [/math] [math](2^{-1}; 1)[/math] [math](2^{-1}; 2)[/math] [math](2^{-2}; 3)[/math]

Выполним объединение первого списка по парам и исключим последний элемент, т.к. для него нет пары:

| Номинал = [math] 2^{-2} [/math] || [math](2^{-1}; 3)[/math] || || |- | Номинал = [math] 2^{-1} [/math] || [math](2^{-1}; 1)[/math] || [math](2^{-1}; 2)[/math] || [math](2^{-2}; 3)[/math] |}