<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=94.45.102.149&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=94.45.102.149&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/94.45.102.149"/>
		<updated>2026-05-08T19:52:28Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%BE%D0%B9%D0%B5%D1%80%D0%B0-%D0%9C%D1%83%D1%80%D0%B0&amp;diff=67000</id>
		<title>Алгоритм Бойера-Мура</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%BE%D0%B9%D0%B5%D1%80%D0%B0-%D0%9C%D1%83%D1%80%D0%B0&amp;diff=67000"/>
				<updated>2018-11-17T11:18:02Z</updated>
		
		<summary type="html">&lt;p&gt;94.45.102.149: /* Псевдокод */ неправильный код, пусть пересмотрят нормальные программисты, бред написан&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Бойера-Мура''', разработанный двумя учеными {{---}} Бойером (Robert S. Boyer) и Муром (J. Strother Moore), считается наиболее быстрым среди алгоритмов общего назначения, предназначенных для поиска подстроки в строке. Важной особенностью алгоритма является то, что он выполняет сравнения в шаблоне справа налево в отличие от многих других алгоритмов.&lt;br /&gt;
&lt;br /&gt;
Алгоритм Бойера-Мура считается наиболее эффективным алгоритмом поиска шаблонов в стандартных приложениях и командах, таких как Ctrl+F в браузерах и текстовых редакторах.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Алгоритм сравнивает символы шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; справа налево, начиная с самого правого, один за другим с символами исходной строки &amp;lt;tex&amp;gt;y&amp;lt;/tex&amp;gt;. Если символы совпадают, производится сравнение предпоследнего символа шаблона и так до конца. Если все символы шаблона совпали с наложенными символами строки, значит, подстрока найдена, и поиск окончен. В случае несовпадения какого-либо символа (или полного совпадения всего шаблона) он использует две предварительно вычисляемых эвристических функций, чтобы сдвинуть позицию для начала сравнения вправо.&lt;br /&gt;
&lt;br /&gt;
Таким образом для сдвига позиции начала сравнения алгоритм Бойера-Мура выбирает между двумя функциями, называемыми эвристиками хорошего суффикса и плохого символа (иногда они называются эвристиками совпавшего суффикса и стоп-символа). Так как функции эвристические, то выбор между ними простой {{---}} ищется такое итоговое значение, чтобы мы не проверяли максимальное число позиций и при этом нашли все подстроки равные шаблону.&lt;br /&gt;
&lt;br /&gt;
Алфавит обозначим буквой &amp;lt;tex&amp;gt;\Sigma&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;|y|=n&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|x|=m&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;|\Sigma|=\sigma&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Предположим, что в процессе сравнения возникает несовпадение между символом &amp;lt;tex&amp;gt;x[i]=a&amp;lt;/tex&amp;gt; шаблона и символом &amp;lt;tex&amp;gt;y[i+j]=b&amp;lt;/tex&amp;gt; исходного текста при проверке в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;x[i+1 \dots m-1]=y[i+j+1 \dots j+m-1]=u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;x[i] \neq y[i+j]&amp;lt;/tex&amp;gt;, и &amp;lt;tex&amp;gt;m - i - 1&amp;lt;/tex&amp;gt; символов шаблона уже совпало.&lt;br /&gt;
&lt;br /&gt;
===Правило сдвига хорошего суффикса===&lt;br /&gt;
Если при сравнении текста и шаблона совпало один или больше символов, шаблон сдвигается в зависимости от того, какой суффикс совпал.&lt;br /&gt;
&lt;br /&gt;
Если существуют такие подстроки равные &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, что они полностью входят в &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; и идут справа от символов, отличных от &amp;lt;tex&amp;gt;x[i]&amp;lt;/tex&amp;gt;, то сдвиг происходит к самой правой из них, отличной от &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt;. Понятно, что таким образом мы не пропустим никакую строку, так как сдвиг просходит на следующую слева подстроку &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; от суффикса. После выравнивания шаблона по этой подстроке сравнение шаблона опять начнется с его последнего символа. На новом шаге алгоритма можно строку &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt;, по которой был произведён cдвиг, не сравнивать с текстом {{---}} возможность для модификации и дальнейшего ускорения алгоритма.&lt;br /&gt;
&lt;br /&gt;
[[Файл:boyer-moore-algorithm-1.png|450px|thumb|center|'''Сдвиг хорошего суффикса''', вся подстрока &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; полностью встречается справа от символа &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, отличного от символа &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
&lt;br /&gt;
Если не существует таких подстрок, то смещение состоит в выравнивании самого длинного суффикса &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; подстроки &amp;lt;tex&amp;gt;y[i+j+1 \dots j+m-1]&amp;lt;/tex&amp;gt; с соответствующим префиксом &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;. Из-за того, что мы не смогли найти такую подстроку, то, очевидно, что ни один суффикс шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; уже не будет лежать в подстроке &amp;lt;tex&amp;gt;y[i+j+1 \dots j+m-1]&amp;lt;/tex&amp;gt;, поэтому единственный вариант, что в эту подстроку попадет префикс.&lt;br /&gt;
&lt;br /&gt;
[[Файл:boyer-moore-algorithm-2.png|450px|thumb|center|'''Сдвиг хорошего суффикса''', только суффикс подстроки &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; повторно встречается в &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
&lt;br /&gt;
===Правило сдвига плохого символа===&lt;br /&gt;
В таблице плохих символов указывается последняя позиция в шаблоне (исключая последнюю букву) каждого из символов алфавита. Для всех символов, не вошедших в шаблон, пишем &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;. Предположим, что у нас не совпал символ &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; из текста на очередном шаге с символом из шаблона. Очевидно, что в таком случае мы можем сдвинуть шаблон до первого вхождения этого символа &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в шаблоне, потому что совпадений других символов точно не может быть. Если в шаблоне такого символа нет, то можно сдвинуть весь шаблон полностью.&lt;br /&gt;
&lt;br /&gt;
Если символ исходного текста &amp;lt;tex&amp;gt;y[i + j]&amp;lt;/tex&amp;gt; встречается в шаблоне &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то происходит его выравнивание с его самым правым появлением в подстроке &amp;lt;tex&amp;gt;x[0 \dots m-2]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:boyer-moore-algorithm-3.png|450px|thumb|center|'''Сдвиг плохого символа''', символ &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; входит в &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;tex&amp;gt;y[i+j]&amp;lt;/tex&amp;gt; не встречается в шаблоне &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то ни одно вхождение &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;y&amp;lt;/tex&amp;gt; не может включать в себя &amp;lt;tex&amp;gt;y[i+j]&amp;lt;/tex&amp;gt;, и левый конец окна сравнения совмещен с символом непосредственно идущим после &amp;lt;tex&amp;gt;y[i+j]&amp;lt;/tex&amp;gt;, то есть символ &amp;lt;tex&amp;gt;y[i+j+1]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:boyer-moore-algorithm-4.png|450px|thumb|center|'''Сдвиг плохого символа''', символ &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; не входит в &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что сдвиг плохого символа может быть отрицательным, поэтому исходя из ранее приведенных свойств этих функций берется значение равное максимуму между сдвигом хорошего суффикса и сдвигом плохого символа.&lt;br /&gt;
&lt;br /&gt;
===Формальное определение===&lt;br /&gt;
&lt;br /&gt;
Теперь определим две функции сдвигов более формально следующим образом:&lt;br /&gt;
&lt;br /&gt;
Пусть значения функции сдвига хорошего суффикса хранятся в массиве &amp;lt;tex&amp;gt;bmGs&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;m+1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Определим два условия:&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{Cs}(i, s)&amp;lt;/tex&amp;gt;: для каждого &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; такого, что &amp;lt;tex&amp;gt;i &amp;lt; k &amp;lt; m&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;s \geqslant k&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;x[k-s]=x[k]&amp;lt;/tex&amp;gt;&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{Co}(i, s)&amp;lt;/tex&amp;gt;: если &amp;lt;tex&amp;gt;s &amp;lt; i&amp;lt;/tex&amp;gt;, то выполняется &amp;lt;tex&amp;gt;x[i-s] \neq x[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда для всех &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; таких, что &amp;lt;tex&amp;gt;0 \leqslant i &amp;lt; m&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;bmGs[i+1]=\min\{s &amp;gt; 0 : \mathrm{Cs}(i, s)\ \wedge\ \mathrm{Co}(i, s)\}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
А значение &amp;lt;tex&amp;gt;bmGs[0]&amp;lt;/tex&amp;gt; определим, как длину периода шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для вычисления &amp;lt;tex&amp;gt; bmGs &amp;lt;/tex&amp;gt; будем использовать функцию &amp;lt;tex&amp;gt;\mathrm{suffixLength}&amp;lt;/tex&amp;gt;, определенную так:&lt;br /&gt;
для всех &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; таких, что &amp;lt;tex&amp;gt;1 \leqslant i &amp;lt; m&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;\mathrm{suffixLength}(i)=\max\{k : x[i-k+1 \dots i]=x[m-k \dots m-1]\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сдвиги плохих символов будем хранить в массиве &amp;lt;tex&amp;gt;bmBc&amp;lt;/tex&amp;gt; размером &amp;lt;tex&amp;gt;\sigma&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Для каждого символа &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;\Sigma&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;bmBc[c] = \begin{cases}&lt;br /&gt;
  \min\{i : 1 \leqslant i &amp;lt; m-1\ \wedge\ x[m-1-i]=c\},  &amp;amp; \mbox{if }  c \in x\\&lt;br /&gt;
  m, &amp;amp; \mbox{otherwise}&lt;br /&gt;
\end{cases}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Массивы &amp;lt;tex&amp;gt;bmBc&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;bmGs&amp;lt;/tex&amp;gt; вычисляются за &amp;lt;tex&amp;gt;O(m^2+\sigma)&amp;lt;/tex&amp;gt; времени до основной фазы поиска и требуют, очевидно, &amp;lt;tex&amp;gt;O(m+\sigma)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
Константой &amp;lt;tex&amp;gt;|\Sigma|=\sigma&amp;lt;/tex&amp;gt; обозначим размер нашего алфавита.&lt;br /&gt;
&lt;br /&gt;
Функция для вычисления таблицы сдвигов плохих символов. Она будет равна длине шаблона для всех символов, которые не встречаются в шаблоне, и порядковому номеру с конца для остальных (кроме последнего, для него тоже берется длина шаблона). Вычисляется прямо по определению за &amp;lt;tex&amp;gt;O(m+\sigma)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   '''int'''[] preBmBc('''char'''[m] x):&lt;br /&gt;
      '''int''' table&amp;lt;tex&amp;gt;[&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;|\Sigma|&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;]&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;font color=green&amp;gt;// Заполняем значением по умолчанию, равным длине шаблона&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''for''' i = 0 .. &amp;lt;tex&amp;gt;|\Sigma|&amp;lt;/tex&amp;gt; - 1&lt;br /&gt;
         table[i] = m&lt;br /&gt;
      &amp;lt;font color=green&amp;gt;// Вычисление функции по определению&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''for''' i = 0 .. m - 2&lt;br /&gt;
         table[x[i]] = m - 1 - i&lt;br /&gt;
      '''return''' table&lt;br /&gt;
&lt;br /&gt;
Функция, проверяющая, что подстрока &amp;lt;tex&amp;gt;x[p \dots m - 1]&amp;lt;/tex&amp;gt; является префиксом шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;. Требует &amp;lt;tex&amp;gt;O(m - p)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
   '''boolean''' isPrefix('''char'''[m] x, '''int''' p):&lt;br /&gt;
      '''int''' j = 0&lt;br /&gt;
      '''for''' i = p .. m - 1&lt;br /&gt;
         '''if''' x[i] != x[j]&lt;br /&gt;
            '''return''' false&lt;br /&gt;
         ++j&lt;br /&gt;
      '''return''' true&lt;br /&gt;
&lt;br /&gt;
Функция, возвращающая для позиции &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; длину максимальной подстроки, которая является суффиксом шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;. Требует &amp;lt;tex&amp;gt;O(m - p)&amp;lt;/tex&amp;gt; времени. //здесь неправильно, нет смысла сравнивать элементы ШАБЛОНА С САМИМ СОБОЙ&lt;br /&gt;
   '''int''' suffixLength('''char'''[m] x, '''int''' p):&lt;br /&gt;
      '''int''' len = 0&lt;br /&gt;
      '''int''' i = p&lt;br /&gt;
      '''int''' j = m - 1&lt;br /&gt;
      '''while''' i &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; 0 '''and''' x[i] == x[j]&lt;br /&gt;
            ++len &lt;br /&gt;
            --i&lt;br /&gt;
            --j&lt;br /&gt;
      '''return''' len&lt;br /&gt;
&lt;br /&gt;
Функция для вычисления сдвигов хороших суффиксов. Требует &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt; времени, несмотря на циклы в вызываемых функциях, из-за того, что каждый внутренний цикл в худшем случае будет выполняться на каждой позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; не больше, чем &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; раз. Получается натуральный ряд, сумма &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; первых членов которого &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{m \cdot (m - 1)}{2}&amp;lt;/tex&amp;gt;. Следовательно, получается оценка по времени &amp;lt;tex&amp;gt;O(m^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   '''int'''[] preBmGs('''char'''[m] x):&lt;br /&gt;
      '''int''' table[m]&lt;br /&gt;
      '''int''' lastPrefixPosition = m&lt;br /&gt;
      '''for''' i = m - 1 .. 0&lt;br /&gt;
         &amp;lt;font color=green&amp;gt;// Если подстрока x[i+1..m-1] является префиксом, то запомним её начало&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''if''' isPrefix(x, i + 1)&lt;br /&gt;
            lastPrefixPosition = i + 1&lt;br /&gt;
         table[m - 1 - i] = lastPrefixPosition - i + m - 1&lt;br /&gt;
      &amp;lt;font color=green&amp;gt;// Вычисление функции по определению&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''for''' i = 0 .. m - 2&lt;br /&gt;
         '''int''' slen = suffixLength(x, i)&lt;br /&gt;
         table[slen] = m - 1 - i + slen&lt;br /&gt;
      '''return''' table&lt;br /&gt;
 &lt;br /&gt;
Основная функция алгоритма Бойера-Мура&lt;br /&gt;
   '''function''' BM('''char'''[n] y, '''char'''[m] x): '''vector &amp;lt;int&amp;gt;'''&lt;br /&gt;
      '''vector &amp;lt;int&amp;gt;''' answer &amp;lt;font color=green&amp;gt;// вектор, содержащий все вхождения подстроки в строку&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''if''' m == 0&lt;br /&gt;
         answer.pushBack(-1) &amp;lt;font color=green&amp;gt;// Искомая подстрока является пустой&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''return''' answer &lt;br /&gt;
      &lt;br /&gt;
      &amp;lt;font color=green&amp;gt;// Предварительные вычисления&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''int'''&amp;lt;tex&amp;gt;[&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;|\Sigma|&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;]&amp;lt;/tex&amp;gt; bmBc = preBmBc(x)&lt;br /&gt;
      '''int'''[m] bmGs = preBmGs(x)&lt;br /&gt;
      &lt;br /&gt;
      &amp;lt;font color=green&amp;gt;// Поиск подстроки&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''for''' i = m - 1 .. n - 1&lt;br /&gt;
         '''int''' j = m - 1&lt;br /&gt;
         '''while''' x[j] == y[i]&lt;br /&gt;
            '''if''' j == 0&lt;br /&gt;
               answer.pushBack(i) &amp;lt;font color=green&amp;gt;// Найдена подстрока в позиции i&amp;lt;/font&amp;gt;&lt;br /&gt;
            --i&lt;br /&gt;
            --j&lt;br /&gt;
         i += max(bmGs[m - 1 - j], bmBc[y[i]])&lt;br /&gt;
      '''if''' (answer == &amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;)&lt;br /&gt;
         answer.pushBack(-1) &amp;lt;font color=green&amp;gt;// Искомая подстрока не найдена&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' answer&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Пусть нам дана строка &amp;lt;tex&amp;gt;y = GCATCGCAGAGAGTATACAGTACG&amp;lt;/tex&amp;gt; и образец &amp;lt;tex&amp;gt;x=GCAGAGAG&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Построим массивы &amp;lt;tex&amp;gt;bmBc&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;bmGs&amp;lt;/tex&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
[[Файл:RaitaPre.png|250px]]&lt;br /&gt;
&lt;br /&gt;
[[Файл:Crochemore.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим шаги алгоритма:&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Изображение !! &amp;lt;tex&amp;gt;(j, bmGs[y[j]])&amp;lt;/tex&amp;gt; !! Описание&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:BMexample1.png|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(7, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Сравниванием последние символы, они неравны, поэтому сдвигаемся на &amp;lt;tex&amp;gt; bmGs[y[j]]&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;y[j]&amp;lt;/tex&amp;gt; {{---}} это не совпавший символ. В данном случае &amp;lt;tex&amp;gt;y[j]=7&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; bmGs[7]= 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:BMexample2.png|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(8, 4)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Последние символы совпали. Предпоследние совпали. Третьи символы с конца различны, сдвигаемся на &amp;lt;tex&amp;gt; bmGs[5]= 4&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:BMexample3.png|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(12, 7)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Последние символы совпали, сравниваем далее. Строчка найдена. Продолжаем работу и сдвигаемся на &amp;lt;tex&amp;gt; bmGs[0]= 7&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:BMexample4.png|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(19, 4)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Последние символы совпали. Предпоследние совпали. Третьи символы с конца различны, сдвигаемся на &amp;lt;tex&amp;gt; bmGs[5]= 4&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:BMexample5.png|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(23, 7)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Последние символы совпали, предпоследние различны. Алгоритм закончил работу.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В итоге, чтобы найти одно вхождение образца длиной &amp;lt;tex&amp;gt;m = 8&amp;lt;/tex&amp;gt; в образце длиной &amp;lt;tex&amp;gt;n = 24&amp;lt;/tex&amp;gt;, нам понадобилось &amp;lt;tex&amp;gt;17&amp;lt;/tex&amp;gt; сравнений символов.&lt;br /&gt;
&lt;br /&gt;
==Асимптотики==&lt;br /&gt;
* Фаза предварительных вычислений требует &amp;lt;tex&amp;gt;O(m^2 + \sigma)&amp;lt;/tex&amp;gt; времени и памяти.&lt;br /&gt;
* В худшем случае поиск требует &amp;lt;tex&amp;gt;O(m \cdot n)&amp;lt;/tex&amp;gt; сравнений.&lt;br /&gt;
* В лучшем случае требует &amp;lt;tex &amp;gt; \Omega \left( \dfrac{n}{m} \right)&amp;lt;/tex&amp;gt; сравнений.&lt;br /&gt;
&lt;br /&gt;
'''Пример:'''&lt;br /&gt;
Исходный текст &amp;lt;tex&amp;gt;bb \dots bb&amp;lt;/tex&amp;gt; и шаблон &amp;lt;tex&amp;gt;abab \dots abab&amp;lt;/tex&amp;gt;. Из-за того, что все символы &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; из текста повторяются в шаблоне &amp;lt;tex&amp;gt;\dfrac{m}{2}&amp;lt;/tex&amp;gt; раз, эвристика хорошего суффикса будет пытаться сопоставить шаблон в каждой позиции (суммарно, &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз), а эвристика плохого символа в каждой позиции будет двигать строку &amp;lt;tex&amp;gt;\dfrac{m}{2}&amp;lt;/tex&amp;gt; раз. Итого, &amp;lt;tex&amp;gt;O(n \cdot m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} длина исходного текста, &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} длина шаблона, &amp;lt;tex&amp;gt;\sigma&amp;lt;/tex&amp;gt; {{---}} размер алфавита.&lt;br /&gt;
&lt;br /&gt;
==Варианты==&lt;br /&gt;
===Алгоритм Бойера — Мура — Хорспула===&lt;br /&gt;
Этот алгоритм работает лучше Бойера-Мура на случайных текстах — для него оценка в среднем лучше.&lt;br /&gt;
Алгоритм использует только сдвиги плохих символов, при этом за такой символ берётся символ из исходного текста, который соответствует последнему символу шаблона, независимо от того, где случилось несовпадение.&lt;br /&gt;
Поскольку реальные поисковые образцы редко имеют равномерное распределение, алгоритм Бойера-Мура-Хорспула может дать как выигрыш, так и проигрыш по сравнению с стандартной реализацией.&lt;br /&gt;
===Алгоритм Чжу — Такаоки===&lt;br /&gt;
На коротких алфавитах сдвиги плохих символов не помогают уже на коротких суффиксах. Простейший способ улучшить работу алгоритма в таких условиях — вместо одного плохого символа строить таблицу для пары символов: несовпавшего и идущего перед ним. Такой алгоритм получил собственное имя: алгоритм Чжу — Такаоки.&lt;br /&gt;
На предварительную обработку расходуется &amp;lt;tex&amp;gt;O(m+\sigma^2)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==Сравнение с другими алгоритмами==&lt;br /&gt;
===Достоинства===&lt;br /&gt;
* Алгоритм Бойера-Мура на хороших данных очень быстр, а вероятность появления плохих данных крайне мала. Поэтому он оптимален в большинстве случаев, когда нет возможности провести предварительную обработку текста, в котором проводится поиск.&lt;br /&gt;
* На больших алфавитах (относительно длины шаблона) алгоритм чрезвычайно быстрый и требует намного меньше памяти, чем [[Алгоритм Ахо-Корасик|алгоритм Ахо-Корасик]].&lt;br /&gt;
* Позволяет добавить множество модификаций, таких как поиск подстроки, включающей ''любой символ (?)'' (но для реализации ''множества символов (*)'' не подходит, так как длина шаблона должна быть известна заранее).&lt;br /&gt;
&lt;br /&gt;
===Недостатки===&lt;br /&gt;
* Алгоритмы семейства Бойера-Мура не расширяются до приблизительного поиска, поиска любой строки из нескольких.&lt;br /&gt;
* На больших алфавитах (например, Юникод) может занимать много памяти. В таких случаях либо обходятся хэш-таблицами, либо дробят алфавит, рассматривая, например, 4-байтовый символ как пару двухбайтовых.&lt;br /&gt;
* На искусственно подобранных неудачных текстах скорость алгоритма Бойера-Мура серьёзно снижается.&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Бойера_—_Мура|Википедия {{---}} Алгоритм Бойера-Мура]]&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Бойера_—_Мура_—_Хорспула|Википедия {{---}} Алгоритм Бойера-Мура-Хорспула]]&lt;br /&gt;
* [[wikipedia:Boyer–Moore_string_search_algorithm|Wikipedia {{---}} Boyer–Moore string search algorithm]]&lt;br /&gt;
* [http://www-igm.univ-mlv.fr/~lecroq/string/node14.html#SECTION00140 Boyer-Moore algorithm]&lt;br /&gt;
* [http://algolist.manual.ru/search/esearch/bm.php Алгоритм Боуера-Мура]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]] &lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;br /&gt;
[[Категория: Точный поиск]]&lt;/div&gt;</summary>
		<author><name>94.45.102.149</name></author>	</entry>

	</feed>