Алгоритм Хаффмана за O(n) — различия между версиями
Aabb (обсуждение | вклад) (ошибка в алгоритме: выход за границу массива) |
м (rollbackEdits.php mass rollback) |
(не показана 1 промежуточная версия 1 участника) | |
(нет различий)
|
Текущая версия на 19:05, 4 сентября 2022
Задача: |
Пусть у нас есть отсортированный по возрастанию алфавит код Хаффмана за . | , . Где — число вхождений символа в строку. Требуется построить
Содержание
Описание алгоритма
Eсли массив не отсортирован, то это можно сделать, например, цифровой сортировкой за , что не ухудшит асимптотику.
Идея алгоритма заключается в том, чтобы создать такую очередь с приоритетами, из которой можно было бы доставать два минимума за , после чего в эту же очередь с приоритетами положить их сумму за . У нас уже есть массив с отсортированными частотами, теперь заведем второй массив, в котором мы будем хранить суммы. На каждой итерации мы будем выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее.
У нас есть три варианта возможных пар минимумов :
- Оба элемента из первого массива.
- Первый элемент первого массива и первый элемент второго массива.
- Два первых элемента второго массива.
Во всех случаях мы дописываем сумму в конец второго массива и передвигаем указатели в массивах на еще не использованные элементы. Докажем, что второй массив остается отсортированным по возрастанию после каждой итерации.
Так как мы выбираем два элемента с наименьшими частотами
и , то в силу выбора элементов их суммарная частота будет не больше суммы двух любых других из нерассмотренных частот, следовательно, никакая из последующих сумм не окажется меньше . Докажем, что не меньше значений, добавленных во второй массив на предыдущих итерациях. Допустим, что это не так и на каком-то шаге мы добавили в массив число такое, что . Это значит, что на одной из итераций мы выбрали два элемента таким образом, что хотя бы один из них был больше либо больше . Но так как первый массив отсортирован по возрастанию, а второй изначально заполнен , это противоречит тому, что на каждой итерации мы выбираем два минимальных значения. Следовательно, наше предположение неверно, сумма является наибольшей из рассмотренных ранее сумм и второй массив отсортирован по возрастанию.На каждом шаге количество элементов уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, поэтому асимптотика программы составляет
.Пример
Для примера возьмем строку "абракадабра".
— указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.
Буква | д | к | б | р | а |
---|---|---|---|---|---|
Массив 1 | 1 | 1 | 2 | 2 | 5 |
Массив 2 |
На первом шаге два минимальных элемента — это первые две ячейки первого массива. Их сумму сохраняем во второй массив.
Буква | д | к | б | р | а |
---|---|---|---|---|---|
Массив 1 | 1 | 1 | 2 | 2 | 5 |
дк | |||||
---|---|---|---|---|---|
Массив 2 | 2 |
На втором шаге снова суммируются первые две ячейки первого массива (нам все равно что взять, первый элемент второго массива или второй элемент первого).
Буква | д | к | б | р | а |
---|---|---|---|---|---|
Массив 1 | 1 | 1 | 2 | 2 | 5 |
дк | бр | ||||
---|---|---|---|---|---|
Массив 2 | 2 | 4 |
На третьем шаге два минимальных элемента — это первые две ячейки второго массива.
Буква | д | к | б | р | а |
---|---|---|---|---|---|
Массив 1 | 1 | 1 | 2 | 2 | 5 |
дк | бр | дкбр | |||
---|---|---|---|---|---|
Массив 2 | 2 | 4 | 6 |
На четвертом шаге складываются две оставшиеся ячейки.
Буква | д | к | б | р | а |
---|---|---|---|---|---|
Массив 1 | 1 | 1 | 2 | 2 | 5 |
дк | бр | дкбр | адкбр | ||
---|---|---|---|---|---|
Массив 2 | 2 | 4 | 6 | 11 |
Псевдокод
Код возвращает число бит, необходимых для кодирования текста с заданным количеством вхождений каждого символа.
int HuffmanCoding(a: int[0..n]):
b: int[0..n]
i, j, ans: int // i, j — указатели в массивах
for k = 0 to n
b[k] =
for k = 0 to n - 1
if a[i] + a[i + 1] <= a[i] + b[j] and a[i] + a[i + 1] <= b[j] + b[j + 1]//уже на 3-ей итерации выход за границу массива
//i = 4, i + 1 = 5, a[5] = undefined
b[k] = a[i] + a[i + 1]
ans += b[k]
i += 2
continue
if a[i] + b[j] <= a[i] + a[i + 1] and a[i] + b[j] <= b[j] + b[j + 1]
b[k] = a[i] + b[j]
ans += b[k]
i++
j++
continue
if b[j] + b[j + 1] <= a[i] + a[i + 1] and b[j] + b[j + 1] <= a[i] + b[j]
b[k] = b[j] + b[j + 1]
ans += b[k]
j += 2
return ans