HTML Diff
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 &lt;= last. Если цикл завершается и кандидат в списке не найден, значит, поиск завершился неудачно - алгоритм вернет false:</p>
66 <p>Цикл следует остановить, когда левая граница станет больше правой. Но в операторе while мы записываем не условие остановки цикла, а условие продолжения, поэтому условие надо поменять на обратное: first &lt;= 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>