65
правок
Изменения
Исправления исправлений части про алгоритмы
== Правосторонний/левосторонний целочисленный двоичный поиск ==
Для простоты дальнейших определений будем считать, что <tex>a[0] = -\infty</tex> и что <tex>a[n+1] = +\infty</tex>(массив нумеруется с <tex>1</tex>).
{{Определение|definition='''Правосторонний бинарный поиск''' (англ. <i>rightside binary search</i>) {{---}} бинарный поиск, с помощью которого мы ищем <tex> \max\limits_{i \in [0,n]} \{i \mid a[i] \leqslant x\} </tex>, где <tex>a</tex> {{---}} массив, а <tex>x</tex> {{---}} искомый ключ}}
Использовав эти два вида двоичного поиска, мы можем найти отрезок позиций <tex>[l,r]</tex> таких, что <tex>\forall i \in [l,r] : a[i] = x</tex> и <tex> \forall i \notin [l,r] : a[i] \neq x </tex>
Задан отсортированный массив <tex>[1, 2, 2, 2, 2, 3, 5, 8, 9, 11], x = 2</tex>.
== Код ==
'''int''' binSearch('''int[]''' a, '''int''' key) : <font color="green">// l, r - левая и правая границыЗапускаем бинарный поиск</font> '''int''' l = 0 <font color="green">// l, r {{---}} левая и правая границы</font>
'''int''' r = len(a) + 1
'''while''' l < r - 1 <font color="green">// запускаем Запускаем цикл</font>
m = (l + r) / 2 <font color="green">// m {{---}} середина области поиска</font>
'''if''' a[m] < key
l = m
'''else'''
r = m <font color="green">// сужение Сужение границ</font>
'''return''' r
== Применение двоичного поиска на некоторых неотсортированных массивах ==
{{Задача|definition = Пусть отсортированный по возрастанию массив из <tex>n</tex> элементов <tex>a[0 \ldots n - 1]</tex>, все элементы которого различны, был циклически сдвинут, требуется максимально быстро найти элемент в таком массиве.}} Если массив, отсортированный по возрастанию, был циклически сдвнут, тогда полученный массив состоит из двух отсортированных частей. Используем двоичный поиск, чтобы найти индекс последнего элемента левой части массива. Для этого в реализации двоичного поиска заменим условие в <code>'''if'''</code> на <tex>a[m] > a[n-1]</tex>, тогда в <tex>l</tex> будет содержаться искомый индекс:
<code>
'''int''' l = 0
'''int''' r = n + 1
'''while''' l < r - 1 <font color="green">// Запускаем циклС помощью бинарного поиска найдем максимум на массиве</font>
m = (l + r) / 2 <font color="green">// m {{---}} середина области поиска</font>
'''if''' a[m] > a[n - 1] <font color="green">// Сужение границ</font>
Время выполнения данного алгоритма {{---}} <tex>O(2\log n)=O(\log n)</tex>.
{{Задача|definition ==='''Применение поиска на массивеМассив образован путем приписывания в конец массива, отсортированном отсортированного по возрастанию, в конец которого приписан массивмассива, отсортированный отсортированного по убыванию'''===. Требуется максимально быстро найти элемент в таком массиве.}}
Найдем индекс последнего элемента массива, отсортированного по возрастанию, воспользовавшись двоичным поиском, условие в <code>'''if'''</code> изменим на <tex>a[m] > a[m - 1]</tex>. Тогда в <tex>l</tex> будет содержаться искомый индекс:
'''int''' l = 0
'''int''' r = n + 1
'''while''' l < r - 1 <font color="green">// Запускаем циклС помощью бинарного поиска найдем точку экстремума на массиве</font>
m = (l + r) / 2 <font color="green">// m {{---}} середина области поиска</font>
'''if''' a[m] > a[m - 1] <font color="green">// Проверяем, возрастает ли массив на данном участке</font>
{{Задача|definition ==='''Применение поиска на двух Два отсортированных по возрастанию массивах, записанных массива записаны один в конец другого'''===. Требуется максимально быстро найти элемент в таком массиве.}}
Мы имеем массив, образованный из двух отсортированных массивовподмассивов, записанных один в конец другого. Рассмотрим разные примеры таких массивов (вертикальная черта означает границу между двумя маленькими массивами, образующими большойзапустить сразу бинарный поиск на таком массиве нельзя, никакой смысловой нагрузки она так как массив не несетбудет обязательно отсортированным. Также нельзя запустить другие поиски, она нужна лишь для облегчения понимания):# работающие за <tex> O( \{ 1, 3, 5 \mid 2, 4, 6 \}log n)</tex> или <tex> \{ 2, 4так как неизвестно количество точек экстремума, 6 \mid 1, 3, 5 \}</tex> {{---}} самые частые вариантыи нет никакой дополнительной информации об элементах в массивах.# <tex> \{ 100 \mid 1 \}</tex> {{---}} оба Поэтому попробуем найти индекс последнего элемента левого массива имеют длину <tex>1</tex>, чтобы потом запустить бинарный поиск два раза на отсортированных массивах.# Рассмотрим массивы <tex> \{ 1,2,3 \mid 4,5,6 \}</tex> {{---}} все элементы из второго массива больше последнего (максимального) элемента из первого массива. Стоит заметить, что массив в этом примере не отличим от массивов: и <tex>\{ 1 \mid ,2,3, 4,5\mid \textbf{0} ,6 \}</tex>(вертикальная черта означает границу между левым и правым массивами): все элементы, <tex>\{ 1кроме пятого не меняются, значит,2 \mid 3по другим элементам невозможно определить,4есть ли в правом массиве элемент,5который меньше элементов левого массива,6 \}поэтому для нахождения конца левого массива придется сравнить все элементы с соседними за <tex>O(n)</tex> и тому подобных, тогда проще сразу искать нужный элемент, а не конец левого массива.
После циклического сдвига мы получим массив <tex>a[0 \ldots n-1]</tex>, образованный из трех частей: отсортированных по возрастанию-убыванию-возрастанию (<tex>\nearrow \searrow \nearrow </tex>) или по убыванию-возрастанию-убыванию (<tex> \searrow \nearrow \searrow </tex>). Поэтому с помощью двоичного поиска мы ищем индексы максимального и минимального элементов массива, заменив условие в <code>'''if'''</code> на <tex>a[m] > a[m - 1]</tex> (ответ будет записан в <tex>l</tex>) или на <tex>a[m] > a[m + 1]</tex> (ответ будет записан в <tex>r</tex>) соответственно.
Затем, в зависимости от расположения частей (можно узнать, сравнив <tex>min</tex> и <tex>max</tex>), запустим двоичный поиск для каждой части отдельно аналогично задаче о поиске элемента на массиве, отсортированном по возрастанию, в конец которого приписан массив, отсортированный по убыванию.
== Источники информации ==
* Д. Кнут {{- --}} Искусство программирования (Том 3, 2-е издание)* [http://ru.wikipedia.org/wiki/%D0%94%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D1%8B%D0%B9_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA Википедия {{--- }} двоичный поиск]
* [http://habrahabr.ru/post/146228/| Интересная статья про типичные ошибки]
* [http://algolist.manual.ru/search/advbin.php| Бинарный поиск на algolist]