Двусторонний алгоритм — различия между версиями
Heatwave (обсуждение | вклад) (→См. также) |
Heatwave (обсуждение | вклад) (Менее адский псевдокод, комментарии) |
||
Строка 36: | Строка 36: | ||
'''function''' twoWaySearch(String pattern, String text): | '''function''' twoWaySearch(String pattern, String text): | ||
− | + | <font color=green>//предобработка <tex>-</tex> вычисление критической позиции (в которой строка делится на <tex>u</tex> и <tex>v</tex>)</font> | |
− | <tex>\langle</tex> | + | <tex>\langle</tex>l1, p1<tex>\rangle</tex> <tex>\leftarrow</tex> maxSuffix(pattern, <tex>\leqslant</tex>) |
− | <tex>\langle</tex> | + | <tex>\langle</tex>l2, p2<tex>\rangle</tex> <tex>\leftarrow</tex> maxSuffix(pattern, <tex>\geqslant</tex>) |
− | '''if''' | + | '''if''' l1 <tex>\geqslant</tex> l2 |
− | + | l = l1 | |
p = p1 | p = p1 | ||
'''else''' | '''else''' | ||
− | len = | + | len = l2 |
p = p2 | p = p2 | ||
+ | <font color=green>//<tex>p</tex> <tex>-</tex> период <tex>x</tex>, <tex>l</tex> <tex>-</tex> такая критическая позиция, что <tex>l<p</tex></font> | ||
occurences = <tex>\varnothing</tex> | occurences = <tex>\varnothing</tex> | ||
pos <tex>\leftarrow</tex> 0 | pos <tex>\leftarrow</tex> 0 | ||
memPrefix <tex>\leftarrow</tex> 0 | memPrefix <tex>\leftarrow</tex> 0 | ||
− | ''' | + | '''while''' pos + pattern.length <tex>\leqslant</tex> text.length |
− | + | <font color=green>//первая фаза: просмотр <tex>v</tex> слева направо</font> | |
− | + | i <tex>\leftarrow \max</tex>(l, memPrefix) + 1 | |
− | + | '''while''' i <tex>\leqslant</tex> pattern.length '''and''' pattern[i] <tex>=</tex> text[pos + i] | |
− | + | i++ | |
− | + | '''if''' i <tex>\leqslant</tex> pattern.length | |
− | + | pos <tex>\leftarrow</tex> pos + <tex>\max</tex>(i <tex>-</tex> l, memPrefix <tex>-</tex> p <tex>+</tex> 1) | |
− | + | memPrefix <tex>\leftarrow</tex> 0 | |
− | + | '''else''' | |
− | + | <font color=green>//вторая фаза: просмотр <tex>u</tex> справа налево</font> | |
− | + | j <tex>\leftarrow</tex> l | |
− | + | '''while''' j <tex> > </tex> memPrefix '''and''' pattern[j] <tex>=</tex> text[pos + j] | |
− | + | j-- | |
− | + | '''if''' j <tex>\leqslant</tex> memPrefix | |
− | + | pos <tex>\rightarrow</tex> occurences | |
− | + | pos <tex>\leftarrow</tex> pos <tex>+</tex> p | |
− | + | memPrefix <tex>\leftarrow</tex> pattern.length <tex>-</tex> p | |
− | |||
− | |||
− | |||
− | '''while''' | ||
− | |||
− | '''if''' | ||
− | pos <tex>\ | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
'''return''' occurences | '''return''' occurences | ||
Версия 00:44, 16 июня 2015
Двусторонний алгоритм (англ. Two Way algorithm) — алгоритм поиска подстроки в строке.
Характерные черты
- требует упорядоченный алфавит,
- этап предобработки занимает времени и константное количество памяти,
- этап поиска за время , где m — длина образца, а n — длина текста.
Описание алгоритма
Строка
разбивается на две части и так, что . Затем фаза поиска в двустороннем алгоритме состоит в сравнении символов слева направо, и затем, если на первом этапе не происходит несовпадений, в сравнении символов справа налево (второй этап). Фаза предобработки, таким образом, заключается в поиске подходящего разбиения .Определение: |
— разбиение строки , если . |
Определение: |
Пусть
| — разбиение . Повторение в — слово такое, что для него выполнены следующие условия:
Определение: |
Длина повторения в | называется локальным периодом; наименьший локальный период записывается как . Каждое разбиение на имеет как минимум одно повторение. Очевидно, что
Определение: |
Разбиение | на такое, что называется критическим разбиением .
Если — критическое разбиение , то на позиции в общий и локальный периоды одинаковы. Двусторонний алгоритм находит критическое разбиение такое, что и длина минимальна.
Чтобы найти критическое разбиение мы сперва вычислим — максимальный суффикс в лексикографическом порядке, характерном для заданного алфавита и максимальный суффикс для обратного лексикографического порядка . Затем выбираются так, что .
Фаза поиска в двустороннем алгоритме состоит из сравнения символов
слева направо и символов справа налево. Когда происходит несовпадение при просмотре -го символа в , производится сдвиг длиной . Когда происходит несовпадение при просмотре или когда образец встретился в строке, производится сдвиг длиной . Такие действия приводят к квадратичной работе алгоритма в худшем случае, но этого можно избежать запоминанием префикса: когда производится сдвиг длиной , длина совпадающего префикса образца в начале "окна" (а именно ) после сдвига запоминается, чтобы не просматривать ее заново при следующем проходе.Псевдокод
function twoWaySearch(String pattern, String text): //предобработкавычисление критической позиции (в которой строка делится на и ) l1, p1 maxSuffix(pattern, ) l2, p2 maxSuffix(pattern, ) if l1 l2 l = l1 p = p1 else len = l2 p = p2 // период , такая критическая позиция, что occurences = pos 0 memPrefix 0 while pos + pattern.length text.length //первая фаза: просмотр слева направо i (l, memPrefix) + 1 while i pattern.length and pattern[i] text[pos + i] i++ if i pattern.length pos pos + (i l, memPrefix p 1) memPrefix 0 else //вторая фаза: просмотр справа налево j l while j memPrefix and pattern[j] text[pos + j] j-- if j memPrefix pos occurences pos pos p memPrefix pattern.length p return occurences