<?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=178.66.54.100&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=178.66.54.100&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/178.66.54.100"/>
		<updated>2026-05-31T03:38:40Z</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%9A%D0%BE%D0%BB%D1%83%D1%81%D1%81%D0%B8&amp;diff=38059</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%9A%D0%BE%D0%BB%D1%83%D1%81%D1%81%D0%B8&amp;diff=38059"/>
				<updated>2014-06-08T15:35:29Z</updated>
		
		<summary type="html">&lt;p&gt;178.66.54.100: /* Алгоритм */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Алгоритм==&lt;br /&gt;
Отметим, что нумерация символов строк и элементов массива у нас начинается с &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Обозначим за &amp;lt;tex&amp;gt;Kmp&amp;lt;/tex&amp;gt; {{---}} [[Префикс-функция|префикс-функцию]], но при этом она определена для &amp;lt;tex&amp;gt;x[0] \dots x[m-1]&amp;lt;/tex&amp;gt; и имеет значение &amp;lt;tex&amp;gt;-1&amp;lt;/tex&amp;gt; по умолчанию.&lt;br /&gt;
&lt;br /&gt;
Множество всех позиций шаблона разделим на два непересекающихся множества. Тогда каждая попытка сравнения шаблона с исходной строкой состоит из двух фаз.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
В первой фазе сравнения выполняются слева направо с символами текста, выровненными с шаблоном в позиции, для которой значение функции &amp;lt;tex&amp;gt;\mathrm{Kmp}(i)&amp;lt;/tex&amp;gt; строго больше &amp;lt;tex&amp;gt;-1&amp;lt;/tex&amp;gt;. Такие позиции будем называть '''насыщенными''' (''noholes'').&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Вторая фаза состоит в сравнении в оставшихся позициях справа налево. Такие позиции будем называть '''ненасыщенными''' (''holes'').&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Такая стратегия предоставляет, как минимум, 2 преимущества:&lt;br /&gt;
* когда несовпадение появляется во время первой фазы, после соответствующего сдвига уже нет необходимости делать проверки в насыщенных позициях, которые были проверены на предыдущем шаге.&lt;br /&gt;
* когда несовпадение появляется во время второй фазы, это означает, что суффикс шаблона совпал с периодом (''factor'') строки, после соответствующего сдвига префикс шаблона будет все ещё совпадать с периодом текста, поэтому нет необходимости в повторной проверке.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Обозначим за &amp;lt;tex&amp;gt;\mathrm{K_{min}}(i) =  \min\{k : \ x[0 \dots i-1-k]=x[d \dots i-1]\ and\ x[i-k] \neq x[i]\}&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;\mathrm{K_{min}}&amp;lt;/tex&amp;gt; для всех позиций &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, у которых &amp;lt;tex&amp;gt;Kmp(i) \neq -1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;tex&amp;gt;\mathrm{Kmin}(i) \neq 0&amp;lt;/tex&amp;gt;, то периодичность шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; заканчивается в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что для &amp;lt;tex&amp;gt;0 &amp;lt; i &amp;lt; m&amp;lt;/tex&amp;gt; позиция &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;:&lt;br /&gt;
* насыщенная, если &amp;lt;tex&amp;gt;\mathrm{Kmin}(i-1) \neq 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
* ненасыщенная, иначе&lt;br /&gt;
&lt;br /&gt;
Обозначим за &amp;lt;tex&amp;gt;nd+1&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;h&amp;lt;/tex&amp;gt; содержит первыми элементами &amp;lt;tex&amp;gt;nd+1&amp;lt;/tex&amp;gt; насыщенных позиций в возрастающем порядке и затем &amp;lt;tex&amp;gt;m-nd-1&amp;lt;/tex&amp;gt; ненасыщенных в убывающем порядке, т.е.&lt;br /&gt;
* для всех &amp;lt;tex&amp;gt;0 \leqslant i \leqslant nd&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;h[i]&amp;lt;/tex&amp;gt; насыщенная позиция и &amp;lt;tex&amp;gt;h[i] &amp;lt; h[i+1]&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;0 \leqslant i &amp;lt; nd&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* для всех &amp;lt;tex&amp;gt;nd &amp;lt; i &amp;lt; m&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;h[i]&amp;lt;/tex&amp;gt; ненасыщенная и &amp;lt;tex&amp;gt;h[i] &amp;gt; h[i+1]&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;nd &amp;lt; i &amp;lt; m-1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Обозначим за &amp;lt;tex&amp;gt;\mathrm{Rmin}(i)&amp;lt;/tex&amp;gt; наименьший период шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; большего, чем &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Обозначим за &amp;lt;tex&amp;gt;\mathrm{First}(u)&amp;lt;/tex&amp;gt; наименьший число &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt;u \leqslant h[v]&amp;lt;/tex&amp;gt;.&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[j \dots j+m-1]&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
== Первая фаза ==&lt;br /&gt;
Рассмотрим случай, когда &amp;lt;tex&amp;gt;x[h[k]]=y[j+h[k]]&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;0 \leqslant k &amp;lt; r &amp;lt; nd&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;x[h[r]] \neq y[j+h[r]]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;j' = j + \mathrm{Kmin}(h[r])&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Тогда нет вхождений шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, начиная с &amp;lt;tex&amp;gt;y[j \dots j']&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; может быть сдвинут на &amp;lt;tex&amp;gt;\mathrm{K_{min}}(h[r])&amp;lt;/tex&amp;gt; позиций вправо.&lt;br /&gt;
&lt;br /&gt;
Кроме того &amp;lt;tex&amp;gt;x[h[k]]=y[j’+h[k]]&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;0 \leqslant k &amp;lt; \mathrm{first}(h[r]-\mathrm{K_{min}}(h[r]))&amp;lt;/tex&amp;gt; означает, что сравнения могут продолжены с &amp;lt;tex&amp;gt;x[h[\mathrm{first}(h[r] - \mathrm{K_{min}}(h[r]))]]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y[j'+h[\mathrm{first}(h[r]-\mathrm{K_{min}}(h[r]))]]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Вторая фаза ==&lt;br /&gt;
Теперь рассмотрим ситуацию, когда &amp;lt;tex&amp;gt;x[h[k]]=y[j+h[k]]&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;0 \leqslant k &amp;lt; r&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;x[h[r]] \neq y[j+h[r]]&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;nd \leqslant r &amp;lt; m&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;j' = j + \mathrm{R_{min}}(h[r])&amp;lt;/tex&amp;gt; позиций вправо. &lt;br /&gt;
&lt;br /&gt;
Тогда нет вхождений шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, начиная с &amp;lt;tex&amp;gt;y[j \dots j']&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; может быть сдвинут на &amp;lt;tex&amp;gt;\mathrm{R_{min}}(h[r])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Кроме того &amp;lt;tex&amp;gt;x[0 \dots m-1-\mathrm{R_{min}}(h[r])]=y[j' \dots j+m-1]&amp;lt;/tex&amp;gt; означает, что сравнения могут продолжены с &amp;lt;tex&amp;gt;x[h[\mathrm{first}(m-1-\mathrm{R_{min}}(h[r]))]]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y[j'+h[\mathrm{first}(m-1-\mathrm{R_{min}}(h[r]))]]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Предварительные вычисления ==&lt;br /&gt;
Для вычисления значений &amp;lt;tex&amp;gt;\mathrm{K_{min}}&amp;lt;/tex&amp;gt; будем использовать вспомогательную функцию &amp;lt;tex&amp;gt;\mathrm{H_{max}}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Обозначим за &amp;lt;tex&amp;gt;\mathrm{H_{max}}&amp;lt;/tex&amp;gt; функцию, для которой выполняется:&lt;br /&gt;
* &amp;lt;tex&amp;gt;x[k \dots \mathrm{H_{max}}(k)-1]=x[0 \dots \mathrm{H_{max}}(k)-k-1]&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* &amp;lt;tex&amp;gt;x[\mathrm{H_{max}}(k)] \neq x[\mathrm{H_{max}}(k)-k]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
'''Наивный вариант'''&lt;br /&gt;
   '''int'''[] buildHmax('''char'''[] x, '''int''' m):&lt;br /&gt;
      '''int''' hmax[m + 1]&lt;br /&gt;
      '''for''' k = 1 .. m&lt;br /&gt;
         '''int''' i = k&lt;br /&gt;
         '''while''' x[i] == x[i - k]&lt;br /&gt;
            i++&lt;br /&gt;
         hmax[k] = i&lt;br /&gt;
      return hmax&lt;br /&gt;
Явная реализация по определению, очевидно, работает за &amp;lt;tex&amp;gt;O(m^2)&amp;lt;/tex&amp;gt; и требует &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
'''Улучшенный вариант'''&lt;br /&gt;
&lt;br /&gt;
   '''int'''[] buildHmax('''char'''[] x, '''int''' m):&lt;br /&gt;
      '''int''' hmax[m + 1]&lt;br /&gt;
      '''int''' i = 1&lt;br /&gt;
      '''int''' k = 1&lt;br /&gt;
      '''while''' k &amp;lt;= m&lt;br /&gt;
         '''while''' x[i] == x[i - k]&lt;br /&gt;
            i++;&lt;br /&gt;
         hmax[k] = i&lt;br /&gt;
         '''int''' q = k + 1&lt;br /&gt;
         '''while''' hmax[q - k] + k &amp;lt; i&lt;br /&gt;
            hmax[q] = hmax[q - k] + k&lt;br /&gt;
            q++&lt;br /&gt;
         k = q&lt;br /&gt;
         if k == i + 1&lt;br /&gt;
            i = k&lt;br /&gt;
      '''return''' hmax&lt;br /&gt;
На каждой итерации цикла увеличивается либо переменная &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; (или переменная &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt;, которая используется в конечном счете для обновления &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;). Поскольку &amp;lt;tex&amp;gt;i = 1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = 1&amp;lt;/tex&amp;gt; в начале и &amp;lt;tex&amp;gt;i &amp;lt; k = m + 1&amp;lt;/tex&amp;gt; в конце алгоритма, количество итераций алгоритма не превосходит &amp;lt;tex&amp;gt;2 \cdot m&amp;lt;/tex&amp;gt;. Следовательно функция требует &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt; времени и памяти.&lt;br /&gt;
&lt;br /&gt;
Функция для построения массива &amp;lt;tex&amp;gt;\mathrm{Kmin}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   '''int'''[] buildKmin('''int'''[] hmax, '''int''' m)&lt;br /&gt;
      '''int''' kmin[m]&lt;br /&gt;
      '''for''' i = m .. 1&lt;br /&gt;
         '''if''' hmax[i] &amp;lt; m&lt;br /&gt;
            kmin[hmax[i]] = i&lt;br /&gt;
      '''return''' kmin&lt;br /&gt;
&lt;br /&gt;
Функция для построения массива &amp;lt;tex&amp;gt;\mathrm{Rmin}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   '''int'''[] buildRmin('''int'''[] hmax, '''int'''[] kmin, '''int''' m)&lt;br /&gt;
      '''int''' rmin[m]&lt;br /&gt;
      '''int''' r = 0&lt;br /&gt;
      '''for''' i = m - 1 .. 0&lt;br /&gt;
         '''if''' hmax[i + 1] == m&lt;br /&gt;
            &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} первое число большее, чем &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и такое, что шаблон имеет период &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
            r = i + 1&lt;br /&gt;
         '''if''' kmin[i] == 0&lt;br /&gt;
            rmin[i] = r&lt;br /&gt;
         '''else'''&lt;br /&gt;
            rmin[i] = 0&lt;br /&gt;
      return rmin&lt;br /&gt;
&lt;br /&gt;
Функция для построение массива &amp;lt;tex&amp;gt;\mathrm{Shift}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   '''int'''[] buildShift('''int'''[] kmin, '''int'''[] rmin, '''int'''[] h, '''int''' nd, '''int''' m)&lt;br /&gt;
      '''int''' shift[m + 1]&lt;br /&gt;
      '''for''' i = 0 .. nd&lt;br /&gt;
         shift[i] = kmin[h[i]]&lt;br /&gt;
      '''for''' i = nd + 1 .. m - 1&lt;br /&gt;
         shift[i] = rmin[h[i]]&lt;br /&gt;
      shift[m] = rmin[0]&lt;br /&gt;
      '''return''' shift&lt;br /&gt;
&lt;br /&gt;
Функция для построения массива &amp;lt;tex&amp;gt;\mathrm{Next}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Асимптотики==&lt;br /&gt;
* partitions the set of pattern positions into two disjoint subsets; the positions in the first set are scanned from left to right and when no mismatch occurs the positions of the second subset are scanned from right to left;&lt;br /&gt;
* preprocessing phase in &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt; time and space complexity;&lt;br /&gt;
* searching phase in &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; time complexity;&lt;br /&gt;
* performs &amp;lt;tex&amp;gt;3/2n&amp;lt;/tex&amp;gt; text character comparisons in the worst case.&lt;br /&gt;
&lt;br /&gt;
==Сравнение с другими алгоритмами==&lt;br /&gt;
===Достоинства===&lt;br /&gt;
* Поиск выполняется за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; в отличие от [[Алгоритм Кнута-Морриса-Пратта|алгоритма Кнута-Морриса-Пратта]], поиск в котором занимается &amp;lt;tex&amp;gt;O(n+m)&amp;lt;/tex&amp;gt;, что помогает уменьшить константу при &amp;lt;tex&amp;gt;m \sim n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Фаза предобработки выполняется за &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt; в отличие от [[Алгоритм Бойера-Мура|алгоритма Бойера-Мура]], где в наилучшем случае можно получить время &amp;lt;tex&amp;gt;O(n+|\Sigma|)&amp;lt;/tex&amp;gt;, что плохо при больших алфавитах.&lt;br /&gt;
&lt;br /&gt;
===Недостатки===&lt;br /&gt;
* Сложность реализации.&lt;br /&gt;
==Источники==&lt;br /&gt;
* COLUSSI L., 1991, Correctness and efficiency of the pattern matching algorithms, Information and Computation 95(2):225-251.&lt;br /&gt;
* [http://www-igm.univ-mlv.fr/~lecroq/string/node10.html Colussi algorithm]&lt;br /&gt;
* [http://alg.csie.ncnu.edu.tw/course/StringMatching/Colussi.ppt Colussi.ppt]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]] &lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>178.66.54.100</name></author>	</entry>

	</feed>