1 added
48 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Мы постоянно что-то ищем с помощью компьютера: номера телефона, свободные номера в гостиницах, товары в интернет-магазинах, квартиры в аренду. Даже сайты мы ищем с помощью поисковой машины. За каждым из этих поисков скрываются разные алгоритмы. Среди них - поиск подстроки, поиск по ключевым словам, префиксный поиск.</p>
1
<p>Мы постоянно что-то ищем с помощью компьютера: номера телефона, свободные номера в гостиницах, товары в интернет-магазинах, квартиры в аренду. Даже сайты мы ищем с помощью поисковой машины. За каждым из этих поисков скрываются разные алгоритмы. Среди них - поиск подстроки, поиск по ключевым словам, префиксный поиск.</p>
2
<p>В этом уроке мы познакомимся с двумя алгоритмами -<strong>методом перебора</strong>и<strong>бинарным поиском</strong>.</p>
2
<p>В этом уроке мы познакомимся с двумя алгоритмами -<strong>методом перебора</strong>и<strong>бинарным поиском</strong>.</p>
3
<h2>Метод перебора</h2>
3
<h2>Метод перебора</h2>
4
<p>Алгоритм перебора проверяет все значения в списке с начала и до нужного атрибута, поэтому его также называют<strong>последовательным</strong>или<strong>линейным поиском</strong>.</p>
4
<p>Алгоритм перебора проверяет все значения в списке с начала и до нужного атрибута, поэтому его также называют<strong>последовательным</strong>или<strong>линейным поиском</strong>.</p>
5
<p>Начнем с самого простого алгоритма перебора -<strong>поиска по списку</strong>.</p>
5
<p>Начнем с самого простого алгоритма перебора -<strong>поиска по списку</strong>.</p>
6
<p>Представим, что мы хотим найти в Google все страницы, на которых встречается фраза "А роза упала на лапу Азора". Слова "роза", "упала" и "лапа" встречаются редко и только в этой фразе, поэтому они значимы для поиска.</p>
6
<p>Представим, что мы хотим найти в Google все страницы, на которых встречается фраза "А роза упала на лапу Азора". Слова "роза", "упала" и "лапа" встречаются редко и только в этой фразе, поэтому они значимы для поиска.</p>
7
<p>А вот слова "а" и "на" встречаются в огромном количестве других запросов и в самых разных предложениях. На результаты поиска они не влияют, потому что поисковые машины исключают их из запроса.</p>
7
<p>А вот слова "а" и "на" встречаются в огромном количестве других запросов и в самых разных предложениях. На результаты поиска они не влияют, потому что поисковые машины исключают их из запроса.</p>
8
<p>Поисковик примет фразу "а роза упала на лапу Азора" и превратит ее в "роза упала лапу Азора". Таким образом он уберет из запроса<strong>стоп-слова</strong>. К ним относятся союзы, частицы, предлоги, междометия и некоторые другие части речи.</p>
8
<p>Поисковик примет фразу "а роза упала на лапу Азора" и превратит ее в "роза упала лапу Азора". Таким образом он уберет из запроса<strong>стоп-слова</strong>. К ним относятся союзы, частицы, предлоги, междометия и некоторые другие части речи.</p>
9
<p>У каждой поисковой машины есть свой список стоп-слов, которые она автоматически исключает из текста. Для примера возьмем такой список стоп-слов в случайном порядке:</p>
9
<p>У каждой поисковой машины есть свой список стоп-слов, которые она автоматически исключает из текста. Для примера возьмем такой список стоп-слов в случайном порядке:</p>
10
<p>Сейчас таблица неудобная - в ней нет какого-либо порядка. Чтобы найти нужное слово, придется постоянно просматривать весь список, тратить время и силы. Работа пойдет быстрее и проще, если упорядочить слова по алфавиту. Слова упорядочены по колонкам:</p>
10
<p>Сейчас таблица неудобная - в ней нет какого-либо порядка. Чтобы найти нужное слово, придется постоянно просматривать весь список, тратить время и силы. Работа пойдет быстрее и проще, если упорядочить слова по алфавиту. Слова упорядочены по колонкам:</p>
11
<p>Рассмотрим более сложный вариант метода перебора -<strong>поиск по ключу</strong>. Такой алгоритм помогает узнать, встречается ли искомое слово в нашем списке. Для примера возьмем массив с европейскими столицами и датами их основания:</p>
11
<p>Рассмотрим более сложный вариант метода перебора -<strong>поиск по ключу</strong>. Такой алгоритм помогает узнать, встречается ли искомое слово в нашем списке. Для примера возьмем массив с европейскими столицами и датами их основания:</p>
12
<p>Какой город основали в 1275 году? Чтобы ответить, придется перебрать все записи в списке, потому что они расположены в случайном порядке.</p>
12
<p>Какой город основали в 1275 году? Чтобы ответить, придется перебрать все записи в списке, потому что они расположены в случайном порядке.</p>
13
<p>Упорядочим города по году основания, и тогда ответ будет очевиден:</p>
13
<p>Упорядочим города по году основания, и тогда ответ будет очевиден:</p>
14
<p>Эти два примера показывают нам два варианта поиска по списку:</p>
14
<p>Эти два примера показывают нам два варианта поиска по списку:</p>
15
<ul><li>В примере со стоп-словами мы проверяли, есть ли слово в списке. Это самый простой вид поиска</li>
15
<ul><li>В примере со стоп-словами мы проверяли, есть ли слово в списке. Это самый простой вид поиска</li>
16
<li>В примере со столицами мы знали один<strong>атрибут</strong>города - год основания, и мы хотели узнать другой атрибут - название. Атрибут, по которому мы ищем, называется<strong>ключом</strong>, а сам метод -<strong>поиском по ключу</strong></li>
16
<li>В примере со столицами мы знали один<strong>атрибут</strong>города - год основания, и мы хотели узнать другой атрибут - название. Атрибут, по которому мы ищем, называется<strong>ключом</strong>, а сам метод -<strong>поиском по ключу</strong></li>
17
</ul><p>По обоим примерам видно, насколько медленно работает метод перебора. В худшем случае алгоритму придется проверить практически все значения в списке.</p>
17
</ul><p>По обоим примерам видно, насколько медленно работает метод перебора. В худшем случае алгоритму придется проверить практически все значения в списке.</p>
18
<p>Представим, что по такому методу работает проверка логина и пароля в Facebook. Массив с логинами-паролями всех пользователей содержит около трех миллиардов элементов. Даже на самых быстрых серверах поиск в массиве занимал бы несколько минут.</p>
18
<p>Представим, что по такому методу работает проверка логина и пароля в Facebook. Массив с логинами-паролями всех пользователей содержит около трех миллиардов элементов. Даже на самых быстрых серверах поиск в массиве занимал бы несколько минут.</p>
19
<p>Чтобы не тратить так много времени на авторизацию в Facebook и работу с другими массивами, можно использовать более быстрый алгоритм.</p>
19
<p>Чтобы не тратить так много времени на авторизацию в Facebook и работу с другими массивами, можно использовать более быстрый алгоритм.</p>
20
<h2>Как ускорить алгоритм перебора</h2>
20
<h2>Как ускорить алгоритм перебора</h2>
21
<p>Мы без труда находим нужную информацию в справочниках и словарях, потому что в них словарные статьи упорядочены. Чтобы работать с такими массивами, люди пользуются неким алгоритмом. Сложность в том, что это происходит на интуитивном уровне - формально описать такой алгоритм непросто.</p>
21
<p>Мы без труда находим нужную информацию в справочниках и словарях, потому что в них словарные статьи упорядочены. Чтобы работать с такими массивами, люди пользуются неким алгоритмом. Сложность в том, что это происходит на интуитивном уровне - формально описать такой алгоритм непросто.</p>
22
<p>В то же время компьютеру нужны конкретные инструкции, так что нам придется превратить интуитивное знание в алгоритм.</p>
22
<p>В то же время компьютеру нужны конкретные инструкции, так что нам придется превратить интуитивное знание в алгоритм.</p>
23
<p>Чтобы это сделать, начнем с простого метода перебора:</p>
23
<p>Чтобы это сделать, начнем с простого метода перебора:</p>
24
-
<p><strong>Javascript</strong></p>
24
+
<p>Функция isStopWord() перебирает<strong>слова-кандидаты</strong>, последовательно сравнивает их с каждой строкой в массиве стоп-слов и возвращает true или false. Мы вставили сюда слова из нашей таблицы, но, чтобы код не получился слишком большим, ограничились десятком слов.</p>
25
-
<p><strong>Python</strong></p>
26
-
<p><strong>PHP</strong></p>
27
-
Java<p>Функция isStopWord() перебирает<strong>слова-кандидаты</strong>, последовательно сравнивает их с каждой строкой в массиве стоп-слов и возвращает true или false. Мы вставили сюда слова из нашей таблицы, но, чтобы код не получился слишком большим, ограничились десятком слов.</p>
28
<p>Разберемся, почему такой поиск работает медленно. На каждом шаге функция двигается к соседнему слову в массиве, чтобы его проверить. В худшем случае она проверяет все слова.</p>
25
<p>Разберемся, почему такой поиск работает медленно. На каждом шаге функция двигается к соседнему слову в массиве, чтобы его проверить. В худшем случае она проверяет все слова.</p>
29
<p>Чтобы ускорить работу, нужно отбрасывать куски массива, где нужного слова точно нет. Пока это невозможно: элементы массива расположены в произвольном порядке, поэтому нужное нам слово может быть где угодно.</p>
26
<p>Чтобы ускорить работу, нужно отбрасывать куски массива, где нужного слова точно нет. Пока это невозможно: элементы массива расположены в произвольном порядке, поэтому нужное нам слово может быть где угодно.</p>
30
<p>Другое дело упорядоченный массив: в нем слова отсортированы по алфавиту. Мы можем не перебирать все элементы, а постепенно отбрасывать лишние фрагменты массива и быстрее искать стоп-слова. В этом поможет<strong>бинарный поиск</strong>.</p>
27
<p>Другое дело упорядоченный массив: в нем слова отсортированы по алфавиту. Мы можем не перебирать все элементы, а постепенно отбрасывать лишние фрагменты массива и быстрее искать стоп-слова. В этом поможет<strong>бинарный поиск</strong>.</p>
31
<h2>Бинарный поиск</h2>
28
<h2>Бинарный поиск</h2>
32
<p>Бинарный поиск - это метод поиска, при котором алгоритм ищет элементы в ограниченной области поиска, причем с каждым шагом область поиска делится на две части.</p>
29
<p>Бинарный поиск - это метод поиска, при котором алгоритм ищет элементы в ограниченной области поиска, причем с каждым шагом область поиска делится на две части.</p>
33
<p>Кратко опишем механизм работы бинарного поиска:</p>
30
<p>Кратко опишем механизм работы бинарного поиска:</p>
34
<ul><li>Бинарный поиск начинается со среднего элемента и на первом шаге идет по всему массиву</li>
31
<ul><li>Бинарный поиск начинается со среднего элемента и на первом шаге идет по всему массиву</li>
35
<li>На каждом шаге область поиска делится пополам, при этом границы поиска задаются первым и последним элементами</li>
32
<li>На каждом шаге область поиска делится пополам, при этом границы поиска задаются первым и последним элементами</li>
36
<li>Алгоритм завершается, когда область поиска сужается до одного элемента</li>
33
<li>Алгоритм завершается, когда область поиска сужается до одного элемента</li>
37
</ul><p>Теперь посмотрим, как выглядит бинарный поиск в нашем примере со стоп-словами.</p>
34
</ul><p>Теперь посмотрим, как выглядит бинарный поиск в нашем примере со стоп-словами.</p>
38
<p>Алгоритм начинается с середины - это слово "который".</p>
35
<p>Алгоритм начинается с середины - это слово "который".</p>
39
<p>Очевидно, что перед ним нет слов "предельно" или "чтобы" - ведь буквы П и Ч в алфавите следуют за К. Если ищем слово "очень", то можем отбросить все слова перед "который" - это практически половина словаря.</p>
36
<p>Очевидно, что перед ним нет слов "предельно" или "чтобы" - ведь буквы П и Ч в алфавите следуют за К. Если ищем слово "очень", то можем отбросить все слова перед "который" - это практически половина словаря.</p>
40
<p>Мы определили, что слово-кандидат может находиться только во второй половине списка. Рядом с К находятся буквы Л и М, так что поблизости от "который" могут быть только слова "лишь" и "мне". Буква О стоит далеко, поэтому и слово "очень" надо искать далеко. Так что заглядываем далеко вперед и попадаем, скажем, на слово "потом".</p>
37
<p>Мы определили, что слово-кандидат может находиться только во второй половине списка. Рядом с К находятся буквы Л и М, так что поблизости от "который" могут быть только слова "лишь" и "мне". Буква О стоит далеко, поэтому и слово "очень" надо искать далеко. Так что заглядываем далеко вперед и попадаем, скажем, на слово "потом".</p>
41
<p>Ситуация со словом "который" повторяется. Теперь О находится перед П, так что мы можем отбросить все слова после "потом".</p>
38
<p>Ситуация со словом "который" повторяется. Теперь О находится перед П, так что мы можем отбросить все слова после "потом".</p>
42
<p>Если мы отбросим все слова перед "который" и после "потом", в нашем распоряжении останется всего четверть от первоначального списка:</p>
39
<p>Если мы отбросим все слова перед "который" и после "потом", в нашем распоряжении останется всего четверть от первоначального списка:</p>
43
<p>Теперь у нас есть<strong>область поиска</strong>. Сначала в область поиска входит весь список, но на каждом шаге она сокращается вдвое. Область поиска можно задать, указав на первое и последнее слово.</p>
40
<p>Теперь у нас есть<strong>область поиска</strong>. Сначала в область поиска входит весь список, но на каждом шаге она сокращается вдвое. Область поиска можно задать, указав на первое и последнее слово.</p>
44
<p>Алгоритм заканчивает работу, когда область поиска сужается до одного слова. Если это наше слово-кандидат, значит поиск завершился успешно.</p>
41
<p>Алгоритм заканчивает работу, когда область поиска сужается до одного слова. Если это наше слово-кандидат, значит поиск завершился успешно.</p>
45
<h3>Как реализовать бинарный поиск</h3>
42
<h3>Как реализовать бинарный поиск</h3>
46
<p>Выше мы описали алгоритм - осталось только превратить его в программу. Формализуем каждый шаг так, чтобы его мог выполнить компьютер.</p>
43
<p>Выше мы описали алгоритм - осталось только превратить его в программу. Формализуем каждый шаг так, чтобы его мог выполнить компьютер.</p>
47
<p>Вот функция, которая проверяет, есть ли слово-кандидат в отсортированном массиве стоп-слов:</p>
44
<p>Вот функция, которая проверяет, есть ли слово-кандидат в отсортированном массиве стоп-слов:</p>
48
-
<p><strong>Javascript</strong></p>
49
-
<p><strong>Python</strong></p>
50
-
<p><strong>PHP</strong></p>
51
-
<p><strong>Java</strong></p>
52
<p>Разберемся, как эта функция работает. На каждом шаге алгоритма мы взаимодействуем с областью поиска. Чтобы определить ее, нам достаточно хранить индексы его первого и последнего элементов. В самом начале область поиска совпадает со всем массивом.</p>
45
<p>Разберемся, как эта функция работает. На каждом шаге алгоритма мы взаимодействуем с областью поиска. Чтобы определить ее, нам достаточно хранить индексы его первого и последнего элементов. В самом начале область поиска совпадает со всем массивом.</p>
53
-
<p><strong>Javascript</strong></p>
54
-
<p><strong>Python</strong></p>
55
-
<p><strong>PHP</strong></p>
56
-
<p><strong>Java</strong></p>
57
<p>Элементы в массивах JavaScript нумеруются с нуля, поэтому сначала индекс первого элемента равен 0, а индекс последнего - на единицу меньше длины массива. Чтобы убедиться в этом, представьте массив, например, из четырех элементов: его элементы будут иметь индексы 0, 1, 2 и 3.</p>
46
<p>Элементы в массивах JavaScript нумеруются с нуля, поэтому сначала индекс первого элемента равен 0, а индекс последнего - на единицу меньше длины массива. Чтобы убедиться в этом, представьте массив, например, из четырех элементов: его элементы будут иметь индексы 0, 1, 2 и 3.</p>
58
<p>На каждом шаге мы сравниваем слово-кандидат со словом из середины области. Найти среднее слово несложно: его индекс находится посередине между первым и последним словом.</p>
47
<p>На каждом шаге мы сравниваем слово-кандидат со словом из середины области. Найти среднее слово несложно: его индекс находится посередине между первым и последним словом.</p>
59
-
<p><strong>Javascript</strong></p>
60
-
<p><strong>Python</strong></p>
61
-
<p><strong>PHP</strong></p>
62
-
<p><strong>Java</strong></p>
63
<p>В массиве с нечетным количеством элементов все просто: у нас есть центральный элемент и две равные половины слева и справа от него. В массиве с четным количеством элементов, длина левой и правой половин будет отличаться на единицу.</p>
48
<p>В массиве с нечетным количеством элементов все просто: у нас есть центральный элемент и две равные половины слева и справа от него. В массиве с четным количеством элементов, длина левой и правой половин будет отличаться на единицу.</p>
64
<p>В нашей формуле это будет означать, что first + last не делится нацело на 2.</p>
49
<p>В нашей формуле это будет означать, что first + last не делится нацело на 2.</p>
65
<p>Чтобы справиться с этой ситуацией, мы округлим это значение вверх или вниз. Если вниз - левая половина будет на один элемент короче правой, а если вверх - наоборот. Можно выбрать любой вариант, алгоритм будет работать в обоих случаях. Округлим значение в меньшую сторону:</p>
50
<p>Чтобы справиться с этой ситуацией, мы округлим это значение вверх или вниз. Если вниз - левая половина будет на один элемент короче правой, а если вверх - наоборот. Можно выбрать любой вариант, алгоритм будет работать в обоих случаях. Округлим значение в меньшую сторону:</p>
66
-
<p><strong>Javascript</strong></p>
67
-
<p><strong>Python</strong></p>
68
-
<p><strong>PHP</strong></p>
69
-
<p><strong>Java</strong></p>
70
<p>Дальше есть три варианта развития событий.</p>
51
<p>Дальше есть три варианта развития событий.</p>
71
<p><strong>Вариант 1:</strong>Слово-кандидат может совпадать со средним словом - поиск завершен с положительным результатом.</p>
52
<p><strong>Вариант 1:</strong>Слово-кандидат может совпадать со средним словом - поиск завершен с положительным результатом.</p>
72
<p><strong>Вариант 2:</strong>Слово-кандидат может быть меньше слова из середины. Тогда надо отбросить все элементы справа и продолжать поиск только в левой части. На следующем шаге первое слово останется прежним, а последнее изменится. Последним словом в новой области поиска станет центральное слово из старой:</p>
53
<p><strong>Вариант 2:</strong>Слово-кандидат может быть меньше слова из середины. Тогда надо отбросить все элементы справа и продолжать поиск только в левой части. На следующем шаге первое слово останется прежним, а последнее изменится. Последним словом в новой области поиска станет центральное слово из старой:</p>
73
-
<p><strong>Javascript</strong></p>
74
-
<p><strong>Python</strong></p>
75
-
<p><strong>PHP</strong></p>
76
-
<p><strong>Java</strong></p>
77
<p>На самом деле мы можем не включать центральное слово в новую область. При проверке первого варианта мы убедились, что слово-кандидат с ним не совпадает. Новым последним словом будет то, которое находится слева от центрального:</p>
54
<p>На самом деле мы можем не включать центральное слово в новую область. При проверке первого варианта мы убедились, что слово-кандидат с ним не совпадает. Новым последним словом будет то, которое находится слева от центрального:</p>
78
-
<p><strong>Javascript</strong></p>
79
-
<p><strong>Python</strong></p>
80
-
<p><strong>PHP</strong></p>
81
-
<p><strong>Java</strong></p>
82
<p><strong>Вариант 3:</strong>Слово-кандидат может быть больше центрального слова. Тогда вместо правой границы надо двигать левую. Код окажется очень похожим:</p>
55
<p><strong>Вариант 3:</strong>Слово-кандидат может быть больше центрального слова. Тогда вместо правой границы надо двигать левую. Код окажется очень похожим:</p>
83
-
<p><strong>Javascript</strong></p>
84
-
<p><strong>Python</strong></p>
85
-
<p><strong>PHP</strong></p>
86
-
<p><strong>Java</strong></p>
87
<p>Мы сократили область поиска вдвое, а теперь надо повторить предыдущие шаги - тогда в нашей программе появится цикл:</p>
56
<p>Мы сократили область поиска вдвое, а теперь надо повторить предыдущие шаги - тогда в нашей программе появится цикл:</p>
88
-
<p><strong>Javascript</strong></p>
89
-
<p><strong>Python</strong></p>
90
-
<p><strong>PHP</strong></p>
91
-
<p><strong>Java</strong></p>
92
<p>Мы пока не знаем условия завершения цикла, поэтому написали три знака вопроса. Чтобы разобраться с условием, обратим внимание, что на каждом шаге первое и последнее слово двигаются к друг другу и когда-нибудь они совпадут. Тогда условие first === last станет истинным.</p>
57
<p>Мы пока не знаем условия завершения цикла, поэтому написали три знака вопроса. Чтобы разобраться с условием, обратим внимание, что на каждом шаге первое и последнее слово двигаются к друг другу и когда-нибудь они совпадут. Тогда условие first === last станет истинным.</p>
93
<p>Если first === last, то формулу (first + last) / 2 можно записать двумя способами:</p>
58
<p>Если first === last, то формулу (first + last) / 2 можно записать двумя способами:</p>
94
<ul><li>(first + first) / 2</li>
59
<ul><li>(first + first) / 2</li>
95
<li>(last + last) / 2</li>
60
<li>(last + last) / 2</li>
96
</ul><p>Индекс центрального элемента в любом случае будет равен first и last.</p>
61
</ul><p>Индекс центрального элемента в любом случае будет равен first и last.</p>
97
<p>Слово-кандидат либо будет совпадать с центральным словом, либо нет. Если оно окажется меньше, у нас выполнится ветка:</p>
62
<p>Слово-кандидат либо будет совпадать с центральным словом, либо нет. Если оно окажется меньше, у нас выполнится ветка:</p>
98
-
<p><strong>Javascript</strong></p>
99
-
<p><strong>Python</strong></p>
100
-
<p><strong>PHP</strong></p>
101
-
<p><strong>Java</strong></p>
102
<p>Мы помним, что значения first, last и middle совпадают, так что новое значение last окажется на единицу меньше first. Ситуация кажется странной - как последнее слово может находиться перед первым?</p>
63
<p>Мы помним, что значения first, last и middle совпадают, так что новое значение last окажется на единицу меньше first. Ситуация кажется странной - как последнее слово может находиться перед первым?</p>
103
<p>Так бывает в<strong>вырожденных случаях</strong>- массивах без элементов для сравнения и с пустой областью поиска. При последнем сравнении слово-кандидат не совпало со словом из списка - значит, его вообще не было в списке.</p>
64
<p>Так бывает в<strong>вырожденных случаях</strong>- массивах без элементов для сравнения и с пустой областью поиска. При последнем сравнении слово-кандидат не совпало со словом из списка - значит, его вообще не было в списке.</p>
104
<p>Такая же ситуация возникнет, если слово-кандидат будет больше среднего слова, но там сработает вторая ветка:</p>
65
<p>Такая же ситуация возникнет, если слово-кандидат будет больше среднего слова, но там сработает вторая ветка:</p>
105
-
<p><strong>Javascript</strong></p>
106
-
<p><strong>Python</strong></p>
107
-
<p><strong>PHP</strong></p>
108
-
<p><strong>Java</strong></p>
109
<p>Цикл следует остановить, когда левая граница станет больше правой. Но в операторе while мы записываем не условие остановки цикла, а условие продолжения, поэтому условие надо поменять на обратное: first <= last. Если цикл завершается и кандидат в списке не найден, значит, поиск завершился неудачно - алгоритм вернет false:</p>
66
<p>Цикл следует остановить, когда левая граница станет больше правой. Но в операторе while мы записываем не условие остановки цикла, а условие продолжения, поэтому условие надо поменять на обратное: first <= last. Если цикл завершается и кандидат в списке не найден, значит, поиск завершился неудачно - алгоритм вернет false:</p>
110
-
<p><strong>Javascript</strong></p>
111
-
<p><strong>Python</strong></p>
112
-
<p><strong>PHP</strong></p>
113
-
<p><strong>Java</strong></p>
114
<h3>Недостатки бинарного поиска</h3>
67
<h3>Недостатки бинарного поиска</h3>
115
<p>На примере списка стоп-слов сравним метод перебора и бинарный поиск. Первое заметное отличие -<strong>бинарный поиск сложнее в реализации</strong>. В нашем случае сортировка метода перебора занимает 8 строк, а бинарный поиск - 18 строк. Стоит ли писать такие сложные программы? Да, если мы ищем по массиву из ста элементов и более.</p>
68
<p>На примере списка стоп-слов сравним метод перебора и бинарный поиск. Первое заметное отличие -<strong>бинарный поиск сложнее в реализации</strong>. В нашем случае сортировка метода перебора занимает 8 строк, а бинарный поиск - 18 строк. Стоит ли писать такие сложные программы? Да, если мы ищем по массиву из ста элементов и более.</p>
116
<p>Если нужно искать в небольших массивах, можно использовать метод перебора - он будет работать со сравнимой скоростью или даже быстрее.</p>
69
<p>Если нужно искать в небольших массивах, можно использовать метод перебора - он будет работать со сравнимой скоростью или даже быстрее.</p>
117
<p>Второе важное ограничение бинарного поиска -<strong>массив всегда должен быть упорядоченным</strong>. Со стоп-словами это ограничение не мешало, потому что это фиксированный список, который надо подготовить всего один раз.</p>
70
<p>Второе важное ограничение бинарного поиска -<strong>массив всегда должен быть упорядоченным</strong>. Со стоп-словами это ограничение не мешало, потому что это фиксированный список, который надо подготовить всего один раз.</p>
118
<p>Но если список не фиксированный и надо добавлять слова во время работы программы, тогда придется писать дополнительный сложный код. Мы не можем просто добавлять слова в конец массива, потому что это нарушит порядок.</p>
71
<p>Но если список не фиксированный и надо добавлять слова во время работы программы, тогда придется писать дополнительный сложный код. Мы не можем просто добавлять слова в конец массива, потому что это нарушит порядок.</p>
119
<p>И третье ограничение - некоторые данные просто нельзя упорядочить. Например, не существует какого-то естественного общепризнанного способа упорядочить цвета:</p>
72
<p>И третье ограничение - некоторые данные просто нельзя упорядочить. Например, не существует какого-то естественного общепризнанного способа упорядочить цвета:</p>
120
<p>Таким же образом, сложно упорядочить пары чисел. Возьмем для примера широту и долготу - это как раз пара чисел:</p>
73
<p>Таким же образом, сложно упорядочить пары чисел. Возьмем для примера широту и долготу - это как раз пара чисел:</p>
121
<ul><li>Самый западный город России - Балтийск, его координаты 54°39′ с. ш. 19°55′ в. д.</li>
74
<ul><li>Самый западный город России - Балтийск, его координаты 54°39′ с. ш. 19°55′ в. д.</li>
122
<li>Самый северный - Певек, координаты 69°42′ с. ш. 170°19′ в. д.</li>
75
<li>Самый северный - Певек, координаты 69°42′ с. ш. 170°19′ в. д.</li>
123
</ul><p>Какие координаты больше? Если бы речь шла только о широте или долготе, мы бы без труда ответили. Но здесь пара чисел: при сравнении широта может оказаться больше, а долгота меньше. Нельзя сказать, что широта важнее долготы или наоборот. Поэтому у координат и других пар чисел нет какого-то естественного и очевидного порядка.</p>
76
</ul><p>Какие координаты больше? Если бы речь шла только о широте или долготе, мы бы без труда ответили. Но здесь пара чисел: при сравнении широта может оказаться больше, а долгота меньше. Нельзя сказать, что широта важнее долготы или наоборот. Поэтому у координат и других пар чисел нет какого-то естественного и очевидного порядка.</p>
124
<p>При этом всегда можно сравнить два цвета или две координаты и узнать, совпадают они или нет. Для таких данных будет работать метод перебора, которому достаточно проверки на равенство. Бинарный поиск не сработает, потому что ему нужно, чтобы данные были больше или меньше.</p>
77
<p>При этом всегда можно сравнить два цвета или две координаты и узнать, совпадают они или нет. Для таких данных будет работать метод перебора, которому достаточно проверки на равенство. Бинарный поиск не сработает, потому что ему нужно, чтобы данные были больше или меньше.</p>
125
<h3>Преимущества бинарного поиска</h3>
78
<h3>Преимущества бинарного поиска</h3>
126
<p>Бинарный поиск быстрее метода перебора, но пока не обсудили, насколько именно он быстрее. Один из способов сравнить производительность на практике - написать программы и измерить время их выполнения.</p>
79
<p>Бинарный поиск быстрее метода перебора, но пока не обсудили, насколько именно он быстрее. Один из способов сравнить производительность на практике - написать программы и измерить время их выполнения.</p>
127
<p>А еще есть теоретический подход - можно сравнивать производительность с помощью рассуждений. Этот навык очень полезен, потому что позволяет отбрасывать плохие решения, не тратя время на разработку программы.</p>
80
<p>А еще есть теоретический подход - можно сравнивать производительность с помощью рассуждений. Этот навык очень полезен, потому что позволяет отбрасывать плохие решения, не тратя время на разработку программы.</p>
128
<p>Сравним время поиска на массивах из 10, 1 000 и 1 000 000 элементов.</p>
81
<p>Сравним время поиска на массивах из 10, 1 000 и 1 000 000 элементов.</p>
129
<p>Что будем сравнивать? В обоих алгоритмах есть цикл. В одном случае он может выполняться 100 раз, а в другом - 50. Это значит, что второй цикл в два раза быстрее первого, хотя мы и не можем назвать точное время в секундах.</p>
82
<p>Что будем сравнивать? В обоих алгоритмах есть цикл. В одном случае он может выполняться 100 раз, а в другом - 50. Это значит, что второй цикл в два раза быстрее первого, хотя мы и не можем назвать точное время в секундах.</p>
130
<p>Проблема в том, что на разных данных количество циклов будет разным.</p>
83
<p>Проблема в том, что на разных данных количество циклов будет разным.</p>
131
<p>В массиве из десяти элементов можно найти число с первого раза, а можно - с десятого. В таких случаях принято считать среднее время выполнения, которое окажется где-то посередине. В среднем, в массиве из десяти элементов, метод перебора найдет нужное число за пять циклов.</p>
84
<p>В массиве из десяти элементов можно найти число с первого раза, а можно - с десятого. В таких случаях принято считать среднее время выполнения, которое окажется где-то посередине. В среднем, в массиве из десяти элементов, метод перебора найдет нужное число за пять циклов.</p>
132
<p>Лучшим для бинарного поиска также окажется один цикл. В худшем случае бинарный поиск пройдет четыре цикла:</p>
85
<p>Лучшим для бинарного поиска также окажется один цикл. В худшем случае бинарный поиск пройдет четыре цикла:</p>
133
<ul><li>Первый поиск - целый массив из 10 элементов</li>
86
<ul><li>Первый поиск - целый массив из 10 элементов</li>
134
<li>Второй - подмассив из пяти элементов</li>
87
<li>Второй - подмассив из пяти элементов</li>
135
<li>Третий - подмассив из двух элементов</li>
88
<li>Третий - подмассив из двух элементов</li>
136
<li>Четвертый - подмассив с одним последним элементом</li>
89
<li>Четвертый - подмассив с одним последним элементом</li>
137
</ul><p>В итоге среднее число циклов для бинарного поиска - 2.</p>
90
</ul><p>В итоге среднее число циклов для бинарного поиска - 2.</p>
138
<p>Сведем результаты в одну таблицу:</p>
91
<p>Сведем результаты в одну таблицу:</p>
139
<p>Как видим, разница в производительности колоссальная, особенно на больших массивах.</p>
92
<p>Как видим, разница в производительности колоссальная, особенно на больших массивах.</p>
140
<h2>Заключение</h2>
93
<h2>Заключение</h2>
141
<ul><li>В уроке мы рассмотрели два алгоритма: метод перебора и бинарный поиск</li>
94
<ul><li>В уроке мы рассмотрели два алгоритма: метод перебора и бинарный поиск</li>
142
<li>У метода перебора есть два варианта:<ul><li>Простой перебор, чтобы проверить, есть ли элемент в списке</li>
95
<li>У метода перебора есть два варианта:<ul><li>Простой перебор, чтобы проверить, есть ли элемент в списке</li>
143
<li>Поиск по ключу, если нужно найти элемент по одному атрибуту</li>
96
<li>Поиск по ключу, если нужно найти элемент по одному атрибуту</li>
144
</ul></li>
97
</ul></li>
145
<li>Бинарный поиск позволяет искать элементы в упорядоченном списке. На каждом шаге алгоритма область поиска делится на две части.</li>
98
<li>Бинарный поиск позволяет искать элементы в упорядоченном списке. На каждом шаге алгоритма область поиска делится на две части.</li>
146
<li>Бинарный поиск гораздо быстрее обычного поиска, но при этом сложнее в реализации</li>
99
<li>Бинарный поиск гораздо быстрее обычного поиска, но при этом сложнее в реализации</li>
147
</ul>
100
</ul>