Алгоритм Кнута - Морріса - Пратта h2>
Реферат p>
Алгоритм Кнута-Моріса-Пратта (КМП) одержує на вхід слово p>
X = x [1] x [2] ... x [n] p>
і переглядає його зліва направо буква за буквою, заповнюючи при
це масив натуральних чисел l [1] ... l [n], де p>
l [i] = длина слова l (x [1] ... х [i]) p>
(функція l визначена в попередньому пункті). Словами: l [i] є
довжина найбільшого початку слова x [1] ... x [i], одночасно є його
кінцем. p>
Яке відношення все це має до пошуку подслова? p>
Іншими словами, як використовувати алгоритм КМП для визначення
того, чи є слово A подсловом слова B? p>
Рішення. Застосуємо алгоритм КМП до слова A # B, де # - спеціальна
буква, не зустрічається ні в A, ні в B. Слово A є подсловом слова B
тоді і тільки тоді, коли серед чисел в масиві l буде число, яке дорівнює довжині
слова A. p>
Описати алгоритм заповнення таблиці l [1] ... l [n]. p>
Рішення. Припустимо, що перший i значень l [1] ... l [i] вже
знайдені. Ми читаємо чергову літеру слова (тобто x [i +1]) і повинні обчислити
l [i +1]. p>
p>
Іншими словами, нас цікавлять початку Z слова p>
x [1] ... x [i +1, p>
що одночасно є його кінцями-з них нам треба брати саме
довге. Звідки беруться ці початку? Кожне з них (не рахуючи порожнього)
виходить з деякого слова Z 'приписуванням букви x [i +1]. Слово Z '
є початком і p>
кінцем слова x [1] ... x [i]. Однак не будь-яке слово, яке є
початком і кінцем слова x [1] ... x [i], годиться - треба, щоб за ним слідувала
буква x [i +1]. p>
Отримуємо такий рецепт відшукання слова Z. Розглянемо всі початку
слова x [1] ... x [i], що є одночасно його кінцями. З них виберемо
підходящі - ті, за якими йде буква x [i +1]. З відповідних виберемо саме
довге. Приписавши в його кінець х [i +1], отримаємо шукане слово Z. Тепер пора
скористатися зробленими нами приготуваннями і згадати, що всі слова,
що є одночасно початками і кінцями даного слова, можна отримати
повторними застосуваннями до нього функції l з попереднього розділу. p>
Ось що виходить: p>
i: = 1; 1 [1]: = 0; p>
(таблиця l [1] .. l [i] заповнена правильно) p>
while i n do begin p>
len: = l [i] p>
(len - довжина початку слова x [1] .. x [i], яке є p>
його кінцем; дедалі довші початку виявилися p>
невідповідними) p>
while (x [len +1] х [i +1]) and (len> 0) do begin p>
(початок не підходить, застосовуємо до нього функцію l) p>
len: = l [len]; p>
end; p>
(знайшли підходяще або переконалися у відсутності) p>
if x [len +1] = x [i +1] do begin p>
(х [1] .. x [len] - найдовше підходяще початок) p>
l [i +1]: = len +1; p>
end else begin p>
(відповідних немає) p>
l [i +1]: = 0; p>
end; p>
i: = i +1; p>
end; p>
Довести, що число дій у наведеному тільки що алгоритм не
перевершує Cn для деякої константи C. p>
Рішення. Це не цілком очевидно: обробка кожної чергової букви
може зажадати багатьох ітерацій у внутрішньому циклі. Однак кожна така
ітерація зменшує len принаймні на 1, і в цьому випадку l [i +1] виявиться
помітно менше l [i]. З іншого боку, при збільшенні i на одиницю величина
l [i] може зрости не більше ніж на 1, так що часто і сильно спадати вона не
може - інакше спадання не буде скомпенсовано зростанням. p>
Більш точно, можна записати нерівність p>
l [i +1]