Двусторонний алгоритм — различия между версиями
Heatwave (обсуждение | вклад) (→Описание алгоритма) |
Heatwave (обсуждение | вклад) м (→Псевдокод) |
||
Строка 35: | Строка 35: | ||
<tex>\langle</tex>len1, p1<tex>\rangle</tex> <tex>\leftarrow</tex> maxSuffix(pattern, <tex>\leqslant</tex>) | <tex>\langle</tex>len1, p1<tex>\rangle</tex> <tex>\leftarrow</tex> maxSuffix(pattern, <tex>\leqslant</tex>) | ||
<tex>\langle</tex>len2, p2<tex>\rangle</tex> <tex>\leftarrow</tex> maxSuffix(pattern, <tex>\geqslant</tex>) | <tex>\langle</tex>len2, p2<tex>\rangle</tex> <tex>\leftarrow</tex> maxSuffix(pattern, <tex>\geqslant</tex>) | ||
− | '''if''' len1 <tex>\geqslant</tex> len2 | + | '''if''' len1 <tex>\geqslant</tex> len2 |
len = len1 | len = len1 | ||
p = p1 | p = p1 | ||
− | '''else''' | + | '''else''' |
len = len2 | len = len2 | ||
p = p2 | p = p2 | ||
Строка 44: | Строка 44: | ||
pos <tex>\leftarrow</tex> 0 | pos <tex>\leftarrow</tex> 0 | ||
memPrefix <tex>\leftarrow</tex> 0 | memPrefix <tex>\leftarrow</tex> 0 | ||
− | '''if''' len < n/2 '''and''' pattern[1<tex>\ldots</tex>len] <tex>-</tex> суффикс pattern[len + 1<tex>\ldots</tex>len + p] | + | '''if''' len < n/2 '''and''' pattern[1<tex>\ldots</tex>len] <tex>-</tex> суффикс pattern[len + 1<tex>\ldots</tex>len + p] |
− | '''while''' pos + n <tex>\leqslant</tex> text.length | + | '''while''' pos + n <tex>\leqslant</tex> text.length |
i <tex>\leftarrow \max</tex>(l, memPrefix) + 1 | i <tex>\leftarrow \max</tex>(l, memPrefix) + 1 | ||
− | '''while''' i <tex>\leqslant</tex> n '''and''' pattern[i] <tex>=</tex> text[pos + i] | + | '''while''' i <tex>\leqslant</tex> n '''and''' pattern[i] <tex>=</tex> text[pos + i] |
i++ | i++ | ||
− | '''if''' i <tex>\leqslant</tex> n | + | '''if''' i <tex>\leqslant</tex> n |
pos <tex>\leftarrow</tex> pos + <tex>\max</tex>(i <tex>-</tex> len, memPrefix <tex>-</tex> p <tex>+</tex> 1) | pos <tex>\leftarrow</tex> pos + <tex>\max</tex>(i <tex>-</tex> len, memPrefix <tex>-</tex> p <tex>+</tex> 1) | ||
memPrefix <tex>\leftarrow</tex> 0 | memPrefix <tex>\leftarrow</tex> 0 | ||
− | '''else''' | + | '''else''' |
j <tex>\leftarrow</tex> l | j <tex>\leftarrow</tex> l | ||
− | '''while''' j <tex> > </tex> memPrefix '''and''' pattern[j] <tex>=</tex> text[pos + j] | + | '''while''' j <tex> > </tex> memPrefix '''and''' pattern[j] <tex>=</tex> text[pos + j] |
j-- | j-- | ||
− | '''if''' j <tex>\leqslant</tex> memPrefix | + | '''if''' j <tex>\leqslant</tex> memPrefix |
pos <tex>\rightarrow</tex> occurences | pos <tex>\rightarrow</tex> occurences | ||
pos <tex>\leftarrow</tex> pos <tex>+</tex> p | pos <tex>\leftarrow</tex> pos <tex>+</tex> p | ||
memPrefix <tex>\leftarrow</tex> n <tex>-</tex> p | memPrefix <tex>\leftarrow</tex> n <tex>-</tex> p | ||
− | '''else''' | + | '''else''' |
q <tex>\leftarrow \max</tex>(len, n <tex>-</tex> len) <tex>+</tex> 1 | q <tex>\leftarrow \max</tex>(len, n <tex>-</tex> len) <tex>+</tex> 1 | ||
− | '''while''' pos + n <tex>\leqslant</tex> text.length | + | '''while''' pos + n <tex>\leqslant</tex> text.length |
i <tex>\leftarrow</tex> len + 1 | i <tex>\leftarrow</tex> len + 1 | ||
− | '''while''' i <tex>\leqslant</tex> n '''and''' pattern[i] <tex>=</tex> text[pos <tex>+</tex> i] | + | '''while''' i <tex>\leqslant</tex> n '''and''' pattern[i] <tex>=</tex> text[pos <tex>+</tex> i] |
i++ | i++ | ||
− | '''if''' i <tex>\leqslant</tex> n | + | '''if''' i <tex>\leqslant</tex> n |
pos <tex>\leftarrow</tex> pos <tex>+</tex> i <tex>-</tex> len | pos <tex>\leftarrow</tex> pos <tex>+</tex> i <tex>-</tex> len | ||
− | '''else''' | + | '''else''' |
j <tex>\leftarrow</tex> len | j <tex>\leftarrow</tex> len | ||
− | '''while''' j <tex> > </tex> 0 '''and''' pattern[j] <tex>=</tex> text[pos <tex>+</tex> j] | + | '''while''' j <tex> > </tex> 0 '''and''' pattern[j] <tex>=</tex> text[pos <tex>+</tex> j] |
j-- | j-- | ||
'''if''' j <tex>=</tex> 0: | '''if''' j <tex>=</tex> 0: |
Версия 14:14, 14 июня 2015
Двусторонний алгоритм (англ. Two Way algorithm) — алгоритм поиска подстроки в строке.
Характерные черты
- требует упорядоченный алфавит
- этап предобработки занимает времени и константное количество памяти
- этап поиска за время
- в худшем случае производится сравнений символов
Описание алгоритма
Строка
разбивается на две части и так, что . Затем фаза поиска в двустороннем алгоритме состоит в сравнении символов слева направо, и затем, если на этом первом этапе не происходит несовпадений, в сравнении символов справа налево (второй этап). Фаза предобработки, таким образом, заключается в поиске подходящего разбиения .Определение: |
Пусть
Иными словами, встречается по обе стороны границы между и и может "залезать" (overflow). Длина повторения в называется локальным периодом; наименьший локальный период записывается как .Каждое разбиение Разбиение на имеет как минимум одно повторение. Очевидно, что на такое, что называется критическим разбиением . | — разбиение . Повторение в — слово такое, что для него выполнены следующие условия:
Если — критическое разбиение , то на позиции в общий и локальный периоды одинаковы. Двусторонний алгоритм находит критическое разбиение такое, что и длина минимальна.
Чтобы найти критическое разбиение мы сперва вычислим — максимальный суффикс в порядке и максимальный суффикс для обратного порядка . Затем выбираются так, что .
Фаза предобработки может быть выполнена за время O(m) и константное количество памяти.
Фаза поиска в двустороннем алгоритме состоит из сравнения символов слева направо и символов справа налево. Когда происходит несовпадение при просмотре -го символа в , производится сдвиг длиной . Когда происходит несовпадение при просмотре , или когда образец встретился в строке, производится сдвиг длиной .
Такие действия приводят к квадратичной работе алгоритма в худшем случае, но этого можно избежать запоминанием префикса: когда производится сдвиг длиной , длина совпадающего префикса образца в начале "окна" (а именно ) после сдвига запоминается, чтобы не просматривать ее заново при следующем проходе.
Фаза поиска может быть выполнена за время .
Двусторонний алгоритм производит сравнений символов в худшем случае; вариация этого алгоритма от Бреслауэра (Breslauer) выполняет менее сравнений и использует константное количество памяти.
Псевдокод
function twoWaySearch(String pattern, String text): n = pattern.lengthlen1, p1 maxSuffix(pattern, ) len2, p2 maxSuffix(pattern, ) if len1 len2 len = len1 p = p1 else len = len2 p = p2 occurences = pos 0 memPrefix 0 if len < n/2 and pattern[1 len] суффикс pattern[len + 1 len + p] while pos + n text.length i (l, memPrefix) + 1 while i n and pattern[i] text[pos + i] i++ if i n pos pos + (i len, 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 n p else q (len, n len) 1 while pos + n text.length i len + 1 while i n and pattern[i] text[pos i] i++ if i n pos pos i len else j len while j 0 and pattern[j] text[pos j] j-- if j 0: pos occurences pos pos q return occurences