Преобразование MTF — различия между версиями
(→Описание алгоритма) |
м (rollbackEdits.php mass rollback) |
||
(не показаны 3 промежуточные версии 3 участников) | |||
Строка 46: | Строка 46: | ||
Пусть дан алфавит размером <tex>M</tex> и строка <tex>S</tex> длиной <tex>N</tex>. Запомним для каждого символа алфавита свой ключ. Изначально <tex>\mathtt{keys}['a'] = 0</tex>, <tex>\mathtt{keys}['b'] = 1</tex>, <tex>\dots</tex> , <tex>\mathtt{keys}['z'] = M-1</tex>. Соединим все вершины в дерево по ключу. | Пусть дан алфавит размером <tex>M</tex> и строка <tex>S</tex> длиной <tex>N</tex>. Запомним для каждого символа алфавита свой ключ. Изначально <tex>\mathtt{keys}['a'] = 0</tex>, <tex>\mathtt{keys}['b'] = 1</tex>, <tex>\dots</tex> , <tex>\mathtt{keys}['z'] = M-1</tex>. Соединим все вершины в дерево по ключу. | ||
− | |||
'''list<int>''' mtf(N): | '''list<int>''' mtf(N): | ||
'''list<int>''' result(N) | '''list<int>''' result(N) | ||
Строка 58: | Строка 57: | ||
merge(cur, tree) <font color=darkgreen> //Объединяем нашу вершину и дерево по ключу</font color=darkgreen> | merge(cur, tree) <font color=darkgreen> //Объединяем нашу вершину и дерево по ключу</font color=darkgreen> | ||
'''return''' result | '''return''' result | ||
− | |||
Функция <tex>\mathtt{findanswer}</tex> считает ответ так: если при спуске из вершины дерева мы должны идти вправо, то прибавляем к ответу количество вершин левого поддерева + 1, иначе ничего не добавляем к ответу. | Функция <tex>\mathtt{findanswer}</tex> считает ответ так: если при спуске из вершины дерева мы должны идти вправо, то прибавляем к ответу количество вершин левого поддерева + 1, иначе ничего не добавляем к ответу. | ||
Строка 107: | Строка 105: | ||
| 0 || 16 || 4/5 || 0 | | 0 || 16 || 4/5 || 0 | ||
|- | |- | ||
− | | 1 || | + | | 1 || 1 || 1/20 || 110 |
|- | |- | ||
− | | 2 || 1 || 1/20 || | + | | 2 || 1 || 1/20 || 111 |
|- | |- | ||
− | | 3 || | + | | 3 || 2 || 1/10 || 10 |
|} | |} | ||
Текущая версия на 19:14, 4 сентября 2022
Определение: |
Преобразование MTF (англ. move-to-front, движение к началу) — алгоритм кодирования, используемый для предварительной обработки данных (обычно потока байтов) перед сжатием, разработанный для улучшения эффективности последующего кодирования. |
Содержание
Описание алгоритма
Изначально каждое возможное значение байта записывается в список (алфавит), в ячейку с номером, равным значению байта, т.е.
. В процессе обработки данных этот список изменяется. По мере поступления очередного символа на выход подается номер элемента, содержащего его значение. После чего этот символ перемещается в начало списка, смещая остальные элементы вправо.Современные алгоритмы (например, bzip2[1]) перед алгоритмом MTF используют алгоритм BWT, поэтому в качестве примера рассмотрим строку , полученную из строки "ABACABA" в результате преобразования Барроуза-Уиллера. Первый символ строки 'B' является вторым элементом алфавита "ABC", поэтому на вывод подаётся . После перемещения 'B' в начало алфавита тот принимает вид "BAC". Дальнейшая работа алгоритма показана в таблице:
Символ | Список | Вывод |
---|---|---|
B | ABC | 1 |
C | BAC | 2 |
A | CBA | 2 |
B | ACB | 2 |
A | BAC | 1 |
A | ABC | 0 |
A | ABC | 0 |
Таким образом, результат работы алгоритма:
.Вот примерная реализация этого алгоритма. Здесь массив
хранит количество символов перед символом , — длина строки .list<int> mtf(N): list<int> result(N) for i = 1 to N result.append(alphabet[S[i]]) помещаем символ S[i] в начало алфавита return result
Данный алгоритм работает за
, где — размер алфавита, — длина строки, что не очень быстро. Этот алгоритм можно реализовать за .Описание алгоритма за O(N log M)
Для решения будем использовать декартово дерево.
Пусть дан алфавит размером
и строка длиной . Запомним для каждого символа алфавита свой ключ. Изначально , , , . Соединим все вершины в дерево по ключу.list<int> mtf(N): list<int> result(N) minkey = 0 for i = 0 to N result.append(findanswer(S[i])) //Считаем ответ cur = find(keys[S[i]]) //Находим вершину в дереве split(cur.key) //Вырезаем вершину из дерева min_key-- //Уменьшаем минимально-возможный ключ cur.key = minkey //Ставим ключ в найденной вершине на минимальный merge(cur, tree) //Объединяем нашу вершину и дерево по ключу return result
Функция
считает ответ так: если при спуске из вершины дерева мы должны идти вправо, то прибавляем к ответу количество вершин левого поддерева + 1, иначе ничего не добавляем к ответу.Функции декартова дерева.
и — стандартные функции для— число, которое меньше любого ключа дерева.
Обратное преобразование
Пусть даны строка
и исходный алфавит "ABC". Символ с номером в алфавите — это 'B'. На вывод подаётся 'B', и этот символ перемещается в начало алфавита. Символ с номером в алфавите — это 'C', поэтому 'C' подается на вывод и перемещается в начало алфавита. Дальнейшее преобразование происходит аналогично.Символ | Список | Вывод |
---|---|---|
1 | ABC | B |
2 | BAC | C |
2 | CBA | A |
2 | ACB | B |
1 | BAC | A |
0 | ABC | A |
0 | ABC | A |
Значит, исходная строка
.Применение
Этот метод позволяет легко преобразовать данные, насыщенные длинными повторами разных символов в блок данных, самыми частыми символами которого будут нули. Без MTF нас подстерегают разного рода трудности в решении проблемы адаптации к данным, поскольку в разных местах данных, полученных на выходе BWT-преобразования, разные символы являются преобладающими. Зачастую мы встречаемся с последовательностями типа "bbbbbcccccdddddaaaaa".
Попробуем сжать эту последовательность при помощи, например, метода Хаффмана. Вероятности всех четырех символов в данном примере равны . Легко посчитать, что в результате кодирования мы получим последовательность длиной бит.
Теперь проделаем то же самое со строкой, подвергнутой MTF-преобразованию (предположим, начальный алфавит выглядит как "abcd").
"bbbbbcccccdddddaaaaa" — исходная строка
"10000200003000030000" — строка после MTF
Символ | Частота | Вероятность | Код Хаффмана |
---|---|---|---|
0 | 16 | 4/5 | 0 |
1 | 1 | 1/20 | 110 |
2 | 1 | 1/20 | 111 |
3 | 2 | 1/10 | 10 |
В результате сжатия получаем последовательность длиной арифметического кодирования для данного примера будет еще значительней.
бит. Стоит заметить, что выигрыш от примененияСм. также
Примечания
Источники информации
- Burrows Wheeler Transform FAQ
- Move-To-Front (Википедия)
- Ryabko, B. Ya. Data compression by means of a «book stack», Problems of Information Transmission, 1980, v. 16: (4), pp. 265–269.
- Ryabko, B. Ya.; Horspool, R. Nigel; Cormack, Gordon V. Comments to: «A locally adaptive data compression scheme» by J. L. Bentley, D. D. Sleator, R. E. Tarjan and V. K. Wei. Comm. ACM 30 (1987), no. 9, 792—794.