<?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=138.68.105.35&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=138.68.105.35&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/138.68.105.35"/>
		<updated>2026-04-18T12:07:11Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BE%D1%85%D0%B2%D0%B0%D1%82%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B0%D1%8F_%D0%BE%D0%BA%D1%80%D1%83%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B0_%D1%82%D0%BE%D1%87%D0%B5%D0%BA&amp;diff=77365</id>
		<title>Минимальная охватывающая окружность множества точек</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BE%D1%85%D0%B2%D0%B0%D1%82%D1%8B%D0%B2%D0%B0%D1%8E%D1%89%D0%B0%D1%8F_%D0%BE%D0%BA%D1%80%D1%83%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B0_%D1%82%D0%BE%D1%87%D0%B5%D0%BA&amp;diff=77365"/>
				<updated>2021-01-10T21:28:46Z</updated>
		
		<summary type="html">&lt;p&gt;138.68.105.35: опечатка&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ready}}&lt;br /&gt;
== Описание ==&lt;br /&gt;
Минимальная охватывающая окружность множества точек (smallest enclosing disc) - это задача, в которой необходимо по заданному набору точек найти окружность минимального радиуса, которая содержит все точки множества.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм ==&lt;br /&gt;
Сперва приведем алгоритм, корректность которого позднее будет доказана.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим метод &amp;lt;tex&amp;gt; MinDisc &amp;lt;/tex&amp;gt;, который будет принимать на вход множество точек, а возвращать будет искомую охватывающую окружность. Идея метода в том, что он генерирует случайную перестановку из точек, которые поступили на вход и в получившимся порядке по одной добавляет их в текущую охватывающую окружность. Как будет доказано позднее, если на каком-то шаге алгоритма текущая точка оказалась вне текущей минимальной окружности, то утверждается, что она лежит на границе новой окружности, которая будет содержать в себе ее и все предыдущие точки. Опишем приведенный выше алгоритм псевдокодом:&lt;br /&gt;
&lt;br /&gt;
 MinDisc(S)&lt;br /&gt;
    Let P - random permutation of S&lt;br /&gt;
    Let D2 - be the smallest enclosing disc for {p1, p2}.&lt;br /&gt;
    for i = 3 to n {&lt;br /&gt;
        if pi &amp;lt;tex&amp;gt; \in &amp;lt;/tex&amp;gt; Di−1  then Di = Di−1 // point is inside. nothing to do here&lt;br /&gt;
                      else Di = MinDiscWithPoint ({p1,...,pi−1}, pi) // point is lying on the boundary of minimal circle&lt;br /&gt;
    }&lt;br /&gt;
    return Dn&lt;br /&gt;
&lt;br /&gt;
Как вы заметили, мы использовали выше метод &amp;lt;tex&amp;gt; MinDiscWithPoint &amp;lt;/tex&amp;gt; - это метод, который по множеству точек и еще одной точке возвращают искомую окружность. При этом выделенная точка (которая передается в качестве второго аргумента) ''обязательно'' лежит ''на'' окружности. Эта функция очень похожа на предыдущую, поэтому приведу лишь ее псевдокод:&lt;br /&gt;
&lt;br /&gt;
 MinDiscWithPoint(S, q)&lt;br /&gt;
    Let P - random permutation of S&lt;br /&gt;
    Let D1 - be the smallest enclosing disc for {p1, q}.&lt;br /&gt;
    for i = 2 to n {&lt;br /&gt;
        if pi &amp;lt;tex&amp;gt; \in &amp;lt;/tex&amp;gt; Di−1  then Di = Di−1 &lt;br /&gt;
                      else Di = MinDiscWith2Points ({p1,...,pi−1}, pi, q) &lt;br /&gt;
    }&lt;br /&gt;
    return Dn&lt;br /&gt;
&lt;br /&gt;
Как и в предыдущем случае мы использовали новый метод. &amp;lt;tex&amp;gt; MinDiscWith2Points &amp;lt;/tex&amp;gt; аналогичен &amp;lt;tex&amp;gt; MinDiscWithPoint &amp;lt;/tex&amp;gt;, но в нем уже передается две точки, которые будут лежать на построенной окружности. В этой функции шафлить инпут не требуется. Опишем его псевдоком:&lt;br /&gt;
&lt;br /&gt;
 MinDiscWith2Points(P, q1, q2)&lt;br /&gt;
    Let D0 - be the smallest enclosing disc for {q1, q2}.&lt;br /&gt;
    for i = 1 to n {&lt;br /&gt;
        if pi &amp;lt;tex&amp;gt; \in &amp;lt;/tex&amp;gt; Di−1  then Di = Di−1 &lt;br /&gt;
                      else Di = сircumcircle (прим. описанная окружность) of a triangle {pi, q1, q2} &lt;br /&gt;
    }&lt;br /&gt;
    return Dn&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; P &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; R &amp;lt;/tex&amp;gt; - два '''непересекающихся''' множества точек на плоскости, Пусть &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt; - некоторая точка из множества &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id= ==lemma==&lt;br /&gt;
|about=лемма 1&lt;br /&gt;
|statement=&lt;br /&gt;
Окружность минимального радиуса, содержащая все точки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; внутри себя и все точки &amp;lt;tex&amp;gt; R &amp;lt;/tex&amp;gt; на границе, ''уникальна''.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:MiniDisc.png|right|310px]]&lt;br /&gt;
Пусть это не так и существует две такие окружности &amp;lt;tex&amp;gt; D_0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D_1 &amp;lt;/tex&amp;gt;. Очевидно, что в таком случае все точки из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; должны лежать внутри &amp;lt;tex&amp;gt; D_0 \cap D_1 &amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt; z &amp;lt;/tex&amp;gt; - точка пересечения окружностей (смотри рисунок). Рассмотрим некоторое семейство окружностей &amp;lt;tex&amp;gt; D(\lambda), 0&amp;lt;=\lambda &amp;lt;= 1 &amp;lt;/tex&amp;gt;. При этом центры этих окружностей лежат на отрезке, соединяющем центры &amp;lt;tex&amp;gt; D_0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D_1 &amp;lt;/tex&amp;gt;, и перемещаются очевидным образом в зависимости от параметра &amp;lt;tex&amp;gt;\lambda &amp;lt;/tex&amp;gt;. При этом радиус каждой из этих окружностей - расстояние от центра до точки &amp;lt;tex&amp;gt; z &amp;lt;/tex&amp;gt;, описанной выше. Рассмотрим окружность &amp;lt;tex&amp;gt; D(1/2) &amp;lt;/tex&amp;gt;. Заметим, что &amp;lt;tex&amp;gt; D_0 \cap D_1 &amp;lt;/tex&amp;gt; лежит целиком внутри нее (по построению окружности &amp;lt;tex&amp;gt; D(1/2) &amp;lt;/tex&amp;gt;), а так как &amp;lt;tex&amp;gt; D(1/2) &amp;lt;/tex&amp;gt; проходит через пересечение окружностей &amp;lt;tex&amp;gt; D_0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D_1 &amp;lt;/tex&amp;gt;, то она проходит через все точки &amp;lt;tex&amp;gt; R &amp;lt;/tex&amp;gt; (так все точки &amp;lt;tex&amp;gt; R &amp;lt;/tex&amp;gt; лежат на &amp;lt;tex&amp;gt; \partial D_0 \cap \partial D_1 &amp;lt;/tex&amp;gt;.). Из этого следует, что эта окружность явлется допустимой для нашей теоремы и при этом обладает '''меньшим''' радиусом, то наше предположение неверно и искомая окружность единственная.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Далее будем называть искомую окружность &amp;lt;tex&amp;gt; md(P, R) &amp;lt;/tex&amp;gt;.''&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id= ==lemma==&lt;br /&gt;
|about=лемма 2&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt; p \in md(P \setminus \{p\}, R) &amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt; md(P, R) = md(P \setminus \{p\}, R) &amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Для множества &amp;lt;tex&amp;gt; P \setminus \{p\} &amp;lt;/tex&amp;gt; справедливо, что для него минимальный диск по определению - это &amp;lt;tex&amp;gt; md(P \setminus \{p\}, R) &amp;lt;/tex&amp;gt;, но так как &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt; лежит внутри него, то он и является корректным диском для множества &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;. Но если бы в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; существовал еще меньший диск, то он бы существовал бы и для &amp;lt;tex&amp;gt; P \setminus \{p\} &amp;lt;/tex&amp;gt;. Значит эти диски равны(в силу единственности) и &amp;lt;tex&amp;gt; md(P, R) = md(P \setminus \{p\}, R) &amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id= ==lemma==&lt;br /&gt;
|about=лемма 3&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt; p \notin md(P \setminus \{p\}, R) &amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt; md(P, R) = md(P \setminus \{p\}, R \cup {p}) &amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; D_0 = md(P \setminus \{p\}, R) &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D_1 = md(P, R)  &amp;lt;/tex&amp;gt;. Рассмотрим аналогичное семейство множеств &amp;lt;tex&amp;gt; D(\lambda) &amp;lt;/tex&amp;gt; как в лемме 1. Зададим это семейство с помощью окружностей  &amp;lt;tex&amp;gt; D_0 &amp;lt;/tex&amp;gt;  и &amp;lt;tex&amp;gt; D_1 &amp;lt;/tex&amp;gt;. Заметим, что &amp;lt;tex&amp;gt; p \notin D_0 &amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt; p \in D_1 &amp;lt;/tex&amp;gt;. Значит найдется такое &amp;lt;tex&amp;gt; \lambda &amp;lt;/tex&amp;gt;, что точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt; лежит на границе окружности &amp;lt;tex&amp;gt; D(\lambda) &amp;lt;/tex&amp;gt;. Но в таком случае так как эта окружность удовлетворяет условиям теоремы и к тому же обладает не большим радиусом, чем &amp;lt;tex&amp;gt; D_1 &amp;lt;/tex&amp;gt; (которая в свою очередь является минимальной охватыающей окружностью), то &amp;lt;tex&amp;gt; \lambda = 1 &amp;lt;/tex&amp;gt;. Это означает, что &amp;lt;tex&amp;gt; D(\lambda) = D_1 &amp;lt;/tex&amp;gt;, то точка &amp;lt;tex&amp;gt; p &amp;lt;/tex&amp;gt; лежит на границе &amp;lt;tex&amp;gt; D_1 &amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt; md(P, R) = md(P \setminus \{p\}, R \cup {p}) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Эти три доказанные леммы полностью подтверждают корректность наших действий в приведенном выше алгоритме, ведь во всех трех методах в условном операторе мы используем леммы 2 и 3, корректность которых доказана. Другими словами, алгоритм действительно найдет искомую минимальную охватывающую окружность множества точек.&lt;br /&gt;
&lt;br /&gt;
==Память и время работы ==&lt;br /&gt;
Сначала разберемся с памятью. Тут все просто - никаких лишних затрат, кроме как на хранение точек нам требуется, то алгоритм требует &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
С временем работы дела обстоят интереснее. На самом деле приведенный алгоритм работает за линейное время. Докажем этот факт.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим некоторое множество &amp;lt;tex&amp;gt; P = \{p_1, ... p_i \} &amp;lt;/tex&amp;gt; и точку &amp;lt;tex&amp;gt; q &amp;lt;/tex&amp;gt;, которая лежит на границе построенной охватывающей окружности.  Тогда попробуем удалить одну точку из набора &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;. Искомая окружность может измениться только в том случае, когда эта удаленная точка лежала на границе, а вероятность этого &amp;lt;tex&amp;gt; 2 / i &amp;lt;/tex&amp;gt; (так как точек, которые образуют нашу окружность не более трех. при этом одна из этих трех точек - &amp;lt;tex&amp;gt; q &amp;lt;/tex&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
То оценим время работы MinDiscWithPoint c помощью доказанного выше факта.  На каждой итерации цикла будет происходить проверка, которая пройдет в &amp;quot;else&amp;quot; с вероятностью &amp;lt;tex&amp;gt; 2 / i &amp;lt;/tex&amp;gt;. А сложность работы каждого &amp;quot;else&amp;quot; - &amp;lt;tex&amp;gt; O(i) &amp;lt;/tex&amp;gt;. То суммарное время работы MinDiscWithPoint вычисляется следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; O(n) + \sum_{i=1}^{n} O(i) * (2 / i ) = O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Абсолютно аналогичным образом доказываем, что время работы &amp;lt;tex&amp;gt; MinDisc &amp;lt;/tex&amp;gt; есть &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. То есть рассматриваемый алгоритм имеет линейную сложность.&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
''Mark de Berg, Otfried Cheong, Marc van Kreveld, Mark Overmars-Computational Geometry Algorithms and Applications, p. 86&lt;br /&gt;
''&lt;/div&gt;</summary>
		<author><name>138.68.105.35</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC&amp;diff=66630</id>
		<title>Двусторонний алгоритм</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B8%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC&amp;diff=66630"/>
				<updated>2018-11-02T20:03:04Z</updated>
		
		<summary type="html">&lt;p&gt;138.68.105.35: /* Ценность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Двусторонний алгоритм''' (англ. ''Two Way algorithm'') — алгоритм [[Поиск подстроки в строке|поиска подстроки в строке]].&lt;br /&gt;
&lt;br /&gt;
==Характерные черты==&lt;br /&gt;
* Требует упорядоченный алфавит,&lt;br /&gt;
* этап предобработки занимает &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt; времени и константное количество памяти,&lt;br /&gt;
* этап поиска за время &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} длина образца, а &amp;lt;tex&amp;gt;n&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;math&amp;gt;u&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; так, что &amp;lt;math&amp;gt;x = uv&amp;lt;/math&amp;gt;. Затем фаза поиска в двустороннем алгоритме состоит в сравнении символов &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; слева направо, и затем, если на первом этапе не происходит несовпадений, в сравнении символов &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; справа налево (второй этап).&lt;br /&gt;
Фаза предобработки, таким образом, заключается в поиске подходящего разбиения &amp;lt;tex&amp;gt;(u, v)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &amp;lt;tex&amp;gt;(u, v)&amp;lt;/tex&amp;gt; {{---}} '''разбиение''' строки &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;x = uv&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = Пусть &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; {{---}} разбиение &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;. '''Повторение''' в &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; {{---}} слово &amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; такое, что для него выполнены следующие условия:&lt;br /&gt;
# &amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; {{---}} суффикс &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; {{---}} суффикс &amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt; {{---}} префикс &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; {{---}} префикс &amp;lt;math&amp;gt;w&amp;lt;/math&amp;gt;.}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = Длина повторения в &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; называется '''локальным периодом'''; наименьший локальный период записывается как &amp;lt;math&amp;gt;r(u, v)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Каждое разбиение &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; имеет как минимум одно повторение. Очевидно, что &amp;lt;math&amp;gt;1 \leqslant r(u, v) \leqslant |x|&amp;lt;/math&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = Разбиение &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; такое, что &amp;lt;math&amp;gt;r(u, v) = per(x)&amp;lt;/math&amp;gt; называется '''критическим разбиением''' &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Если &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; {{---}} критическое разбиение &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;, то на позиции &amp;lt;math&amp;gt;|u|&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; общий и локальный периоды одинаковы. Двусторонний алгоритм находит критическое разбиение &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; такое, что &amp;lt;math&amp;gt;|u| &amp;lt; per(x)&amp;lt;/math&amp;gt; и длина &amp;lt;math&amp;gt;|u|&amp;lt;/math&amp;gt; минимальна.&lt;br /&gt;
Чтобы найти критическое разбиение &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; мы сперва вычислим &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; {{---}} максимальный суффикс &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; в лексикографическом порядке, характерном для заданного алфавита &amp;lt;math&amp;gt;\leqslant&amp;lt;/math&amp;gt; и максимальный суффикс &amp;lt;math&amp;gt;\widetilde{z}&amp;lt;/math&amp;gt; для обратного лексикографического порядка &amp;lt;math&amp;gt;\geqslant&amp;lt;/math&amp;gt;. Затем &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; выбираются так, что &amp;lt;math&amp;gt;|u| = \max(|z|, |\widetilde{z}|)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Фаза поиска в двустороннем алгоритме состоит из сравнения символов &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; слева направо и символов &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; справа налево. Когда происходит несовпадение при просмотре &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;-го символа в &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, производится сдвиг длиной &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;. Когда происходит несовпадение при просмотре &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; или когда образец встретился в строке, производится сдвиг длиной &amp;lt;math&amp;gt;per(x)&amp;lt;/math&amp;gt;.&lt;br /&gt;
Такие действия приводят к квадратичной работе алгоритма в худшем случае, но этого можно избежать запоминанием префикса: когда производится сдвиг длиной &amp;lt;math&amp;gt;per(x)&amp;lt;/math&amp;gt;, длина совпадающего префикса образца в начале &amp;quot;окна&amp;quot; (а именно &amp;lt;math&amp;gt;m - per(x)&amp;lt;/math&amp;gt;) после сдвига запоминается, чтобы не просматривать ее заново при следующем проходе.&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
&lt;br /&gt;
 '''function''' twoWaySearch('''String''' pattern, '''String''' text): '''vector&amp;lt;int&amp;gt;'''&lt;br /&gt;
     &amp;lt;font color=green&amp;gt;//предобработка &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; вычисление критической позиции (в которой строка делится на &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&amp;lt;/font&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\langle&amp;lt;/tex&amp;gt;l1, p1&amp;lt;tex&amp;gt;\rangle&amp;lt;/tex&amp;gt; = maxSuffix(pattern, &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt;)&lt;br /&gt;
     &amp;lt;tex&amp;gt;\langle&amp;lt;/tex&amp;gt;l2, p2&amp;lt;tex&amp;gt;\rangle&amp;lt;/tex&amp;gt; = maxSuffix(pattern, &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt;)&lt;br /&gt;
     &amp;lt;tex&amp;gt;\langle&amp;lt;/tex&amp;gt;l, p&amp;lt;tex&amp;gt;\rangle&amp;lt;/tex&amp;gt; = l1 &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; l2 ? &amp;lt;tex&amp;gt;\langle&amp;lt;/tex&amp;gt;l1, p1&amp;lt;tex&amp;gt;\rangle&amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt;\langle&amp;lt;/tex&amp;gt;l2, p2&amp;lt;tex&amp;gt;\rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;font color=green&amp;gt;//&amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; период &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; такая критическая позиция, что &amp;lt;tex&amp;gt;l&amp;lt;p&amp;lt;/tex&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''vector&amp;lt;int&amp;gt; ''' occurences  &amp;lt;font color=green&amp;gt;// набор всех вхождений образца в текст&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''int''' pos = 0&lt;br /&gt;
     '''int''' memPrefix = 0&lt;br /&gt;
     '''while''' pos + pattern.length &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; text.length&lt;br /&gt;
     &amp;lt;font color=green&amp;gt;//первый этап: просмотр &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; слева направо&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''int''' i = max(l, memPrefix) + 1&lt;br /&gt;
         '''while''' i &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; pattern.length '''and''' pattern[i] = text[pos + i]&lt;br /&gt;
             i++&lt;br /&gt;
         '''if''' i &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; pattern.length&lt;br /&gt;
             pos = pos + max(i - l, memPrefix - p + 1)&lt;br /&gt;
             memPrefix = 0&lt;br /&gt;
         '''else'''&lt;br /&gt;
             &amp;lt;font color=green&amp;gt;//второй этап: просмотр &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; справа налево&amp;lt;/font&amp;gt;&lt;br /&gt;
             '''int''' j = l&lt;br /&gt;
             '''while''' j &amp;lt;tex&amp;gt; &amp;gt; &amp;lt;/tex&amp;gt; memPrefix '''and''' pattern[j] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; text[pos + j]&lt;br /&gt;
                 j--&lt;br /&gt;
             '''if''' j &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; memPrefix&lt;br /&gt;
                 occurences.pushBack(pos)  &lt;br /&gt;
             pos = pos + p&lt;br /&gt;
             memPrefix = pattern.length - p&lt;br /&gt;
     '''return''' occurences&lt;br /&gt;
&lt;br /&gt;
== Ценность алгоритма ==&lt;br /&gt;
Двусторонний алгоритм отчасти похож на алгоритм Бойера-Мура (просмотр символов справа налево и сдвиг позиции при несовпадении на втором этапе), и в лучшем случае работает немногим медленнее его, а в худшем {{---}} значительно превосходит&amp;lt;ref&amp;gt;[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] Оценки скорости работы&amp;lt;/ref&amp;gt;, но главное отличие двустороннего алгоритма от алгоритмов Кнута-Морриса-Пратта и Бойера-Мура {{---}} константное количество затрачиваемой дополнительной памяти.&lt;br /&gt;
&lt;br /&gt;
Именно этот алгоритм (в несколько модифицированном виде) используется в реализации поиска подстроки в glibc&amp;lt;ref&amp;gt;[https://github.com/bminor/glibc/blob/glibc-2.28/string/strstr.c#L88 Реализация функции strstr в glibc]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм Кнута-Морриса-Пратта ]]&lt;br /&gt;
* [[Алгоритм Бойера-Мура]]&lt;br /&gt;
&lt;br /&gt;
== Примечания ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://monge.univ-mlv.fr/~mac/Articles-PDF/CP-1991-jacm.pdf  Оригинал статьи (M. Crochemore, D. Perrin)]&lt;br /&gt;
* [http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260  Краткое описание алгоритма, пример работы]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Поиск подстроки в строке]]&lt;br /&gt;
[[Категория:Точный поиск]]&lt;/div&gt;</summary>
		<author><name>138.68.105.35</name></author>	</entry>

	</feed>