9.3. РАСПОЗНАВАНИЕ ПОДЦЕПОЧЕК
 
Важным частным случаем общей проблемы, описанной в предыдущем разделе, является случай, когда регулярное выражение а имеет вид  где каждый член
 где каждый член  цепочка в алфавите
 цепочка в алфавите  Из следствия теоремы 9.5 вытекает, что первое вхождение цепочки-образа
 Из следствия теоремы 9.5 вытекает, что первое вхождение цепочки-образа  в цепочку-текст
 в цепочку-текст  можно найти за
 можно найти за  шагов, где I — сумма длин цепочек i Однако возможно решение и сложности
 шагов, где I — сумма длин цепочек i Однако возможно решение и сложности  Сначала рассмотрим случай, когда дана только одна цепочка-образ
 Сначала рассмотрим случай, когда дана только одна цепочка-образ  где каждый символ
 где каждый символ  принадлежит
 принадлежит  
 
По цепочке у построим детерминированную машину  для идентификации цепочек, которая распознает кратчайшую цепочку из
 для идентификации цепочек, которая распознает кратчайшую цепочку из  входящую в х. Чтобы построить
 входящую в х. Чтобы построить  построим сначала скелетный
 построим сначала скелетный  состояниями
 состояниями  который переходит из состояния
 который переходит из состояния  в состояние
 в состояние  на входном символе
 на входном символе  как показано на рис. 9.12. Состояние
 как показано на рис. 9.12. Состояние  имеет также переход в себя при всех
 имеет также переход в себя при всех  Состояние I можно считать указателем на
 Состояние I можно считать указателем на  позицию цепочки-образа у.
 позицию цепочки-образа у. 
Машина идентификации цепочек  работает как детерминированный конечный автомат с той лишь разницей, что, просматривая один входной символ, она может сделать несколько переходов
 работает как детерминированный конечный автомат с той лишь разницей, что, просматривая один входной символ, она может сделать несколько переходов  
 
 
Рис. 9.12. Скелетная машина. 
(изменений состояния).  имеет то же множество состояний, что и скелетная машина. Поэтому состояние
 имеет то же множество состояний, что и скелетная машина. Поэтому состояние  машины
 машины  соответствует префиксу
 соответствует префиксу  цепочки-образа у.
 цепочки-образа у. 
М начинает работу в состоянии  и с входным указателем на
 и с входным указателем на  т. е. на первый символ цепочки-текста
 т. е. на первый символ цепочки-текста  Если
 Если  то
 то  переходит в состояние 1 и сдвигает входной указатель на вторую позицию цепочки-текста. Если
 переходит в состояние 1 и сдвигает входной указатель на вторую позицию цепочки-текста. Если  то
 то  остается в состоянии
 остается в состоянии  и сдвигает входной указатель на вторую позицию.
 и сдвигает входной указатель на вторую позицию. 
Допустим, что  после прочтения
 после прочтения  находится в состоянии
 находится в состоянии  Это означает, что последние
 Это означает, что последние  символов цепочки
 символов цепочки  совпадают с
 совпадают с  а последние
 а последние  символов в
 символов в  не являются префиксом цепочки
 не являются префиксом цепочки  для
 для  Если
 Если  т. е. следующий входной символ, совпадает с
 т. е. следующий входной символ, совпадает с  то
 то  переходит в состояние
 переходит в состояние  и сдвигает входной указатель на
 и сдвигает входной указатель на  Если
 Если  то
 то  переходит в наибольшее состояние
 переходит в наибольшее состояние  для которого
 для которого  суффикс цепочки
 суффикс цепочки  
 
Чтобы облегчить нахождение состояния  с машиной
 с машиной  связывается функция
 связывается функция  принимающая целочисленные значения. Она называется функцией отказов и задается так:
 принимающая целочисленные значения. Она называется функцией отказов и задается так:  наибольшее число
 наибольшее число  для которого
 для которого  суффикс цепочки
 суффикс цепочки  т. е.
 т. е.  Если такого
 Если такого  нет, то
 нет, то  
 
Пример 9.7. Пусть  Функция
 Функция  принимает значения
 принимает значения
 
Например,  ибо
 ибо  самый длинный собственный префикс цепочки
 самый длинный собственный префикс цепочки  который является ее суффиксом.
 который является ее суффиксом. 
Алгоритм вычисления функции отказов мы изложим несколько позже. Сейчас, чтобы увидеть, как функция отказов используется машиной  определим функцию
 определим функцию  
 
 
Иными словами,  эта та же функция
 эта та же функция  примененная
 примененная  раз к
 раз к  (В примере
 (В примере  )
) 
Снова предположим, что  после прочтения
 после прочтения  находится в состоянии
 находится в состоянии  В этот момент
 В этот момент  итерирует
 итерирует 
 
применение функции отказов к  до тех пор, пока не обнаруживается наименьшее значение
 до тех пор, пока не обнаруживается наименьшее значение  для которого либо
 для которого либо 
 
Таким образом,  движется назад через состояния
 движется назад через состояния  до тех пор, пока не встретит такое
 до тех пор, пока не встретит такое  что условие 1 или 2 будет выполнено для
 что условие 1 или 2 будет выполнено для  но не для
 но не для  Если выполнилось условие 2, то
 Если выполнилось условие 2, то  переходит в состояние 0. В любом случае входной указатель сдвигается на
 переходит в состояние 0. В любом случае входной указатель сдвигается на  
 
В случае 1 легко проверить, что поскольку  самый длинный префикс цепочки у, который являлся суффиксом цепочки
 самый длинный префикс цепочки у, который являлся суффиксом цепочки  то
 то  самый длинный префикс цепочки у, который является суффиксом цепочки
 самый длинный префикс цепочки у, который является суффиксом цепочки  В случае 2 никакой префикс цепочки у не является суффиксом цепочки ахаг.
 В случае 2 никакой префикс цепочки у не является суффиксом цепочки ахаг.  
 
Затем  обрабатывает входной символ
 обрабатывает входной символ  и продолжает работать по такой схеме до момента, когда либо попадет в заключительное состояние I (и тогда I последних просмотренных входных символов образуют вхождение цепочки
 и продолжает работать по такой схеме до момента, когда либо попадет в заключительное состояние I (и тогда I последних просмотренных входных символов образуют вхождение цепочки  либо обработает последний входной символ из х и не попадет в состояние I (и тогда у не является подцепочкой цепочки
 либо обработает последний входной символ из х и не попадет в состояние I (и тогда у не является подцепочкой цепочки  
 
Пример 9.8. Пусть  Машина идентификации цепочек
 Машина идентификации цепочек  изображена на рис. 9.13. Штриховые стрелки указывают значения функции отказов для всех состояний. На входе
 изображена на рис. 9.13. Штриховые стрелки указывают значения функции отказов для всех состояний. На входе  машина
 машина  пройдет через такую последовательность состояний:
 пройдет через такую последовательность состояний: 
 
Например, вначале машина  находится в состоянии 0. Прочитав первый символ из х, она переходит в состояние 1. Так как из состояния 1 нет перехода по второму входному символу
 находится в состоянии 0. Прочитав первый символ из х, она переходит в состояние 1. Так как из состояния 1 нет перехода по второму входному символу  то
 то  переходит в состояние 0, т. е. в значение функции отказов для состояния 1, при этом входной указатель не сдвигается. Так как первый символ в у отличен от
 переходит в состояние 0, т. е. в значение функции отказов для состояния 1, при этом входной указатель не сдвигается. Так как первый символ в у отличен от  то выполнено условие 2, и
 то выполнено условие 2, и  остается в состоянии
 остается в состоянии  и сдвигает входной указатель на позицию 3.
 и сдвигает входной указатель на позицию 3. 
 
Рис. 9.13. Машина идентификации цепочек. 
 
Теорема 9.6. Алгоритм 9.2 вычисляет  
 
Доказательство. Докажем индукцией по  что
 что  такое наибольшее целое
 такое наибольшее целое  что
 что  Если такого
 Если такого  нет, то
 нет, то  
 
По определению  Допустим, что предположение индукции верно для всех При вычислении
 Допустим, что предположение индукции верно для всех При вычислении  алгоритм 9.2, выполняя строку 4, сравнивает с
 алгоритм 9.2, выполняя строку 4, сравнивает с  
 
Случай 1. Пусть  Поскольку
 Поскольку  это такое наибольшее
 это такое наибольшее  что
 что  равенство
 равенство  выполняется. Таким образом, в строках
 выполняется. Таким образом, в строках  вычисляется правильно.
 вычисляется правильно. 
Случай 2. Пусть  Тогда надо найти наибольшее значение
 Тогда надо найти наибольшее значение  для которого
 для которого  если такое
 если такое  существует. Если такого
 существует. Если такого  нет, то очевидно, что
 нет, то очевидно, что  правильно вычисляется в строке 5. Пусть
 правильно вычисляется в строке 5. Пусть  наибольшее, второе по величине и т. д. значения
 наибольшее, второе по величине и т. д. значения  для которых
 для которых 
 
С помощью простой индукции убеждаемся, что  поскольку
 поскольку  по величине значение
 по величине значение  для которого
 для которого  наибольшее значение
 наибольшее значение  Для которого
 Для которого  Строка
 Строка  по очереди, пока не найдет такое
 по очереди, пока не найдет такое  что
 что  если такое
 если такое  существует. По окончании выполнения
 существует. По окончании выполнения  -оператора будет
-оператора будет  если такое
 если такое  существует, и, значит,
 существует, и, значит,  правильно вычисляется в строке 5.
 правильно вычисляется в строке 5. 
Таким образом,  правильно вычисляется для всех
 правильно вычисляется для всех  
 
Теорема 9.7. Алгоритм 9.2 вычисляет  за
 за  шагов.
 шагов. 
Доказательство. Строки 3 и 5 имеют фиксированную сложность. Сложность  -оператора пропорциональна числу уменьшений значения
-оператора пропорциональна числу уменьшений значения  оператором
 оператором  который стоит после
 который стоит после  в строке 4. Единственный способ увеличить
 в строке 4. Единственный способ увеличить  это присвоить
 это присвоить  в строке 6, затем увеличить
 в строке 6, затем увеличить  на 1 в строке 2 и положить
 на 1 в строке 2 и положить  в строке 3. Поскольку вначале
 в строке 3. Поскольку вначале  а строка 6 выполняется не более
 а строка 6 выполняется не более  раз, заключаем, что
 раз, заключаем, что  -оператор в строке 4 не может выполняться более I раз. Поэтому строка 4 требует
-оператор в строке 4 не может выполняться более I раз. Поэтому строка 4 требует  времени. Остальная часть алгоритма, очевидно, имеет сложность
 времени. Остальная часть алгоритма, очевидно, имеет сложность  и потому весь алгоритм тратит
 и потому весь алгоритм тратит  времени.
 времени.  
С помощью тех же рассуждений, что и в теореме 9.6, можно доказать, что после прочтения слова  машина идентификации образов
 машина идентификации образов  будет находиться в состоянии
 будет находиться в состоянии  тогда и только тогда, когда
 тогда и только тогда, когда  самый длинный префикс цепочки у, который является суффиксом цепочки
 самый длинный префикс цепочки у, который является суффиксом цепочки  Поэтому машина
 Поэтому машина  
  
 
правильно находит самое левое вхождение цепочки у в цепочку-текст  
 
С помощью тех же рассуждений, что и в теореме 9.7, можно доказать, что при обработке входной цепочки х машина  изменит свое состояние не более
 изменит свое состояние не более  раз. Поэтому можно узнать, является ли у подцепочкой цепочки х, проследив изменения состояния машины
 раз. Поэтому можно узнать, является ли у подцепочкой цепочки х, проследив изменения состояния машины  на входе х Для этого надо лишь знать значение функции отказов на у. По теореме 9.7 эти значения функции
 на входе х Для этого надо лишь знать значение функции отказов на у. По теореме 9.7 эти значения функции  можно найти за время
 можно найти за время  Следовательно, узнать, является ли у подцепочкой цепочки х, можно за время
 Следовательно, узнать, является ли у подцепочкой цепочки х, можно за время  не зависящее от размера алфавита. Если же алфавит цепочки-образа мал, а цепочка-текст значительно длиннее образа, то можно смоделировать некоторый
 не зависящее от размера алфавита. Если же алфавит цепочки-образа мал, а цепочка-текст значительно длиннее образа, то можно смоделировать некоторый  допускающий язык
 допускающий язык  Этот ДКА в точности один раз меняет состояние на каждом входном символе.
 Этот ДКА в точности один раз меняет состояние на каждом входном символе. 
Алгоритм 9.3. Построение ДКА для  
 
Вход. Цепочка-образ  в алфавите
 в алфавите  Для удобства вводим новый символ
 Для удобства вводим новый символ 
Выход.  для которого
 для которого  
 
Метод. 
1. Алгоритмом 9.2 строим функцию отказов  для у.
 для у. 
2. Пусть  где
 где  а 6 определяется так:
 а 6 определяется так: 
 
Теорема 9.8. Алгоритм 9.3 строит такой  что
 что
 
тогда и только тогда, когда  суффикс цепочки
 суффикс цепочки  но
 но  при
 при  не является суффиксом для
 не является суффиксом для  
 
Доказательство. Доказательство проводится индукцией по А с помощью тех же рассуждений, что и в теореме 9.6. Оставляем его читателю. 
Пример  для
 для  построенный алгоритмом 9.3, изображен на рис. 9.15.
 построенный алгоритмом 9.3, изображен на рис. 9.15. 
На входе  автомат
 автомат  делает такие переходы:
 делает такие переходы: 
 
 
Рис. 9.15. Детерминированный конечный автомат, допускающий  
 
 
Единственное отличие его от  состоит в том, что
 состоит в том, что  заранее вычисляет состояние, в которое следует переходить в случае несовпадения. Поэтому он делает в точности один переход на каждом входном символе.
 заранее вычисляет состояние, в которое следует переходить в случае несовпадения. Поэтому он делает в точности один переход на каждом входном символе.  
 
Основные результаты раздела суммируем в следующей теореме. 
Теорема 9.9. За время  можно выяснить, является ли у подцепочкой цепочки х.
 можно выяснить, является ли у подцепочкой цепочки х. 
Теперь разберем случай, когда даны несколько цепочек-образов  Наша задача — распознать, входит ли одна из цепочек
 Наша задача — распознать, входит ли одна из цепочек  в данную цепочку
 в данную цепочку  . К этой задаче можно также применить методы данного раздела. Сначала построим скелетную машину для
. К этой задаче можно также применить методы данного раздела. Сначала построим скелетную машину для  Она будет деревом. На этом дереве вычислим функцию отказов за время, пропорциональное
 Она будет деревом. На этом дереве вычислим функцию отказов за время, пропорциональное  Потом тем же способом, что и раньше, построим машину идентификации образов. Тогда за
 Потом тем же способом, что и раньше, построим машину идентификации образов. Тогда за  шагов мы узнаем, является ли какая-нибудь цепочка
 шагов мы узнаем, является ли какая-нибудь цепочка  подцепочкой цепочки х. Детали оставляем в качестве упражнения.
 подцепочкой цепочки х. Детали оставляем в качестве упражнения.