Двусторонний алгоритм — различия между версиями
Heatwave (обсуждение | вклад)  (Менее адский псевдокод, комментарии)  | 
				Heatwave (обсуждение | вклад)   | 
				||
| Строка 50: | Строка 50: | ||
      memPrefix <tex>\leftarrow</tex> 0  |       memPrefix <tex>\leftarrow</tex> 0  | ||
      '''while''' pos + pattern.length <tex>\leqslant</tex> text.length  |       '''while''' pos + pattern.length <tex>\leqslant</tex> text.length  | ||
| − |       <font color=green>//  | + |       <font color=green>//первый этап: просмотр <tex>v</tex> слева направо</font>  | 
          i <tex>\leftarrow \max</tex>(l, memPrefix) + 1  |           i <tex>\leftarrow \max</tex>(l, memPrefix) + 1  | ||
          '''while''' i <tex>\leqslant</tex> pattern.length '''and''' pattern[i] <tex>=</tex> text[pos + i]  |           '''while''' i <tex>\leqslant</tex> pattern.length '''and''' pattern[i] <tex>=</tex> text[pos + i]  | ||
| Строка 58: | Строка 58: | ||
              memPrefix <tex>\leftarrow</tex> 0  |               memPrefix <tex>\leftarrow</tex> 0  | ||
          '''else'''  |           '''else'''  | ||
| − |               <font color=green>//  | + |               <font color=green>//второй этап: просмотр <tex>u</tex> справа налево</font>  | 
              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]  | ||
| Строка 67: | Строка 67: | ||
              memPrefix <tex>\leftarrow</tex> pattern.length <tex>-</tex> p  |               memPrefix <tex>\leftarrow</tex> pattern.length <tex>-</tex> p  | ||
      '''return''' occurences  |       '''return''' occurences  | ||
| + | |||
| + | == Ценность алгоритма ==  | ||
| + | Двусторонний алгоритм отчасти похож на алгоритм Бойера-Мура (просмотр символов справа налево и сдвиг позиции при несовпадении на втором этапе), и в лучшем случае работает немногим медленнее его, а в худшем {{---}} значительно превосходит<ref>[http://monge.univ-mlv.fr/~mac/Articles-PDF/CP-1991-jacm.pdf Journal of the Association for Computing Machinery, Vol. 38, No, 1, July 1991] Оценки скорости работы</ref>, но главное отличие двустороннего алгоритма от алгоритмов Кнута-Морриса-Пратта и Бойера-Мура {{---}} константное количество затрачиваемой дополнительной памяти.   | ||
== Источники информации ==  | == Источники информации ==  | ||
* [http://monge.univ-mlv.fr/~mac/Articles-PDF/CP-1991-jacm.pdf  Оригинал статьи (M. Crochemore, D. Perrin)]  | * [http://monge.univ-mlv.fr/~mac/Articles-PDF/CP-1991-jacm.pdf  Оригинал статьи (M. Crochemore, D. Perrin)]  | ||
* [http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260  Краткое описание алгоритма, пример работы]  | * [http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260  Краткое описание алгоритма, пример работы]  | ||
| + | |||
| + | == Примечания ==  | ||
| + | <references/>  | ||
== См. также ==  | == См. также ==  | ||
Версия 01:37, 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
Ценность алгоритма
Двусторонний алгоритм отчасти похож на алгоритм Бойера-Мура (просмотр символов справа налево и сдвиг позиции при несовпадении на втором этапе), и в лучшем случае работает немногим медленнее его, а в худшем — значительно превосходит[1], но главное отличие двустороннего алгоритма от алгоритмов Кнута-Морриса-Пратта и Бойера-Мура — константное количество затрачиваемой дополнительной памяти.
Источники информации
Примечания
- ↑ Journal of the Association for Computing Machinery, Vol. 38, No, 1, July 1991 Оценки скорости работы