Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
сиаод_ответы_16_79.doc
Скачиваний:
209
Добавлен:
11.05.2015
Размер:
7.84 Mб
Скачать

71. Поиск подстрок. Алгоритм Рабина-Карпа

Алгоритм Рабина — Карпа — это алгоритм поиска строки, который ищет шаблон, то есть подстроку, в тексте, используя хеширование. Он был разработан в 1987 году Майклом Рабином и Ричардом Карпом.

Алгоритм редко используется для поиска одиночного шаблона, но имеет значительную теоретическую важность и очень эффективен в поиске совпадений множественных шаблонов. Для текста длины n и шаблона длины m его среднее время исполнения и лучшее время исполнения - это O(n), но в (весьма нежелательном) худшем случае он имеет производительность O(nm), что является одной из причин того, почему он не слишком широко используется. Однако алгоритм имеет уникальную особенность находить любую из k строк менее чем за время O(n) в среднем, независимо от размера k.

Одно из простейших практических применений алгоритма Рабина — Карпа состоит в определении плагиата. Скажем, например, что студент пишет работу по Моби Дику. Коварный профессор находит различные исходные материалы поМоби Дику и автоматически извлекает список предложений в этих материалах. Затем, алгоритм Рабина — Карпа может быстро найти в проверяемой статье примеры вхождения некоторых предложений из исходных материалов. Для устранения чувствительности алгоритма к небольшим различиям, можно игнорировать детали, такие как регистр или пунктуация при помощи их удаления. Поскольку количество строк, которые мы ищем, k, очень большое, обычные алгоритмы поиска одиночных строк становятся неэффективными.

RK(T[1..n],P[1..m],d,q)

  1. h←dm-1modq

  2. p←0

  3. t←0

  4. for i=1 to m do

  5. p←(p*d+p[i])modq

  6. t←(t*d+T[i])modq

  7. end for

  8. for S=0 to n-m do

  9. if p=t then

  10. if (P[1..m] = T[s+1..s+m]) then

  11. print(“Обработка входящих со сдвигом”,s)

  12. if s<n-m then

  13. t←((t-T[s+1]*k)d+T[S+m+k])modq

  14. end for

72 Равномерный и неравномерный код. Префиксное кодирование.

Более короткие коды не совпадают с более длинными. Например, есть код {«0»,«10»,«11»}.

Допустим, а=0; b=10; c=11.

Тогда сообщение abac закодируем:”010011”, а можно ли преобразовать обратно? Первый символ – а однозначно. Следующий 1 полностью не определяет символ, «10» - b, следующий – a, после с.

Например, есть текст a,b,c,d,e,f. В файле 100 000 символов, причем а – 45 000, b – 13 000, c – 12 000, d – 16 000, e – 9 000, f – 5 000.

Посмотрим, как влияет кодирование на размер файла:

  1. Равномерный код.

Так как 6 символов кодируем в 3 битовом коде:

a=000, b=0001, c=010, d=011, e=100, f=101. Соответственно файл будет 300 000 бит.

  1. Неравномерный код.

Те числа, что встречаются часто кодируем короткими битами, редкие – длинными. A=0, b=101, c=100, d=111, e=1101, f=1100.

Для представления используем кодовые деревья.

Известными алгоритмами построения кодовых деревьев являются алгоритм Хофмана, Фано-Шенона.

73. Алгоритм Шеннона – Фано

Алгоритм Шеннона — Фано — один из первых алгоритмов сжатия, который впервые сформулировали американские учёные Шеннон и Фано. Алгоритм использует коды переменной длины: часто встречающийся символ кодируется кодом меньшей длины, редко встречающийся — кодом большей длины. Основные этапы: 1) Символы первичного алфавита m1 выписывают в порядке убывания вероятностей. 2)Символы полученного алфавита делят на две части, суммарные вероятности символов которых максимально близки друг другу. 3)В префиксном коде для первой части алфавита присваивается двоичная цифра «0», второй части — «1». 4)Полученные части рекурсивно делятся и их частям назначаются соответствующие двоичные цифры в префиксном коде. Код Шеннона — Фано строится с помощью дерева. Построение этого дерева начинается от корня. Всё множество кодируемых элементов соответствует корню дерева (вершине первого уровня). Оно разбивается на два подмножества с примерно одинаковыми суммарными вероятностями. Эти подмножества соответствуют двум вершинам второго уровня, которые соединяются с корнем. Далее каждое из этих подмножеств разбивается на два подмножества с примерно одинаковыми суммарными вероятностями. Им соответствуют вершины третьего уровня. Если подмножество содержит единственный элемент, то ему соответствует концевая вершина кодового дерева; такое подмножество разбиению не подлежит. Подобным образом поступаем до тех пор, пока не получим все концевые вершины. Ветви кодового дерева размечаем символами 1 и 0. Пример кодового дерева: Исходные символы: A (частота встречаемости 50), В(частота встречаемости 39), C (18), D (49), E (35), F (24).

Полученный код: A — 11, B — 101, C — 100, D — 00, E — 011, F — 010.

Алгоритм Fano(P[1..n])

C:array [1..n][1..L] of 0..1

  1. Fano1(1,n,0)

Fano1(b,e,k)

  1. If e>b then

  2. K←k+1

  3. m←Med(b,e)

  4. For i=b to e do

  5. If i<=m then k-ому коду i-ого символа

  6. C[I,k] ←0

  7. Else C[I,k] ←1

  8. Fano1(b,m,k)

  9. Fano1(m+1,e,k)

  10. End if

Med(b,e)

  1. Sb ←0

  2. For i=b to e-1 do

  3. Sb ←Sb+P[i]

  4. Se ←P[e]

  5. m ←e

  6. repeat

  7. d ←Sb-Se

  8. m ←m-1

  9. Sb ←Sb-P[m]; Se ←Se+P[m]

  10. Until |Sb-Se|>=d

  11. Return m