* placeholder * 0413更新 * 0413删除comments * 第四章第一节进行一对一修改,发现几个核心问题,后续不再重复叙述。具体问题参见具体说明 因为该版本不会被用在最后的校对输出中,后续不再复制纸质版原文,只标注出现不一致的部分 1.非程序部分大量出现文本和纸质版不一致,已全部修改,AI翻译版本没有纸质版自然 2.程序部分python部分就和纸质版不一致,但是其他程序和AI翻译的python一致,建议让AI先搬运纸质版python的翻译,再加工其他的部分,翻译水平尚可。 3.程序部分AI翻译版本不稳定,大部分使用动宾结构表达,少部分使用动名词结构,出现少量语法错误。纸质版大多使用动名词结构 4.相对中文在线版格式未出现问题,该部分表现较好 * 第四章后续章节未精确修改和俄语版不一致的部分,因为从第一节可以看出,AI基本上都是自己翻的。 在这里标出了所有应该修改的部分 除了第一节以外新增的问题: 1.程序部分出现语法错误 2.单复数问题在程序和标题中出现多次,正文中更是屡见不鲜 3.程序部分,python错了之后,后续的程序全部参照python一起错,建议统一修改,还是参照python但是一起修改掉 * 第十章第一节整体检查 1.正文部分和纸质版的重叠仍然基本没有,都是AI翻译 2.程序部分除了python和纸质版翻译不一致以外,出现较为严重的术语错误 3.接下来的四节内容我将不再展示正文部分的不一致,以上已经可以充分说明了 * 第十章后续章节梳理(该部分仍然绝大部分的内容都和纸质版完全不一致,从措辞到表达方法都不一致,包括正文也包括程序) 考虑到还需要进行AI设计,在此没有重复标注 其他问题: 1.正文中有一些细节,比如说引号的删除、大小写的确认、 2.程序上也出现了术语错误和语法错误 * docs(ru): refine wording after sentence-level Chinese comparison --------- Co-authored-by: Veronica <[email protected]> Co-authored-by: krahets <[email protected]>
8.9 KiB
Двоичный поиск
Двоичный поиск (binary search) - это эффективный алгоритм поиска, основанный на стратегии «разделяй и властвуй». Он использует упорядоченность данных, сокращая на каждом шаге область поиска вдвое, пока не будет найден целевой элемент или область поиска не станет пустой.
!!! question
Дан массив `nums` длины $n$, элементы которого расположены в порядке возрастания и не повторяются. Найдите и верните индекс элемента `target` в этом массиве. Если массив не содержит этого элемента, верните $-1$ . Пример показан на рисунке ниже.
Как показано на рисунке ниже, сначала инициализируем указатели i = 0 и j = n - 1 , которые указывают на первый и последний элементы массива и задают интервал поиска [0, n - 1] . Обратите внимание: квадратные скобки обозначают замкнутый интервал и включают граничные значения.
Далее в цикле выполняются следующие два шага.
- Вычислить индекс середины
m = \lfloor {(i + j) / 2} \rfloor, где\lfloor \: \rfloorозначает операцию округления вниз. - Сравнить
nums[m]иtarget, после чего возможны три случая.- Если
nums[m] < target, это означает, чтоtargetнаходится в интервале[m + 1, j], поэтому выполняетсяi = m + 1. - Если
nums[m] > target, это означает, чтоtargetнаходится в интервале[i, m - 1], поэтому выполняетсяj = m - 1. - Если
nums[m] = target, значит, элементtargetнайден, поэтому возвращается индексm.
- Если
Если массив не содержит целевой элемент, область поиска в итоге сузится до пустого интервала. В этом случае возвращается -1 .
Стоит отметить, что поскольку и i , и j имеют тип int , то сумма i + j может выйти за пределы диапазона типа int. Чтобы избежать переполнения, обычно используют формулу m = \lfloor {i + (j - i) / 2} \rfloor для вычисления середины.
Код приведен ниже:
[file]{binary_search}-[class]{}-[func]{binary_search}
Временная сложность равна $O(\log n)$ : в цикле двоичного поиска интервал каждый раз сокращается вдвое, поэтому число итераций равно \log_2 n .
Пространственная сложность равна $O(1)$ : указатели i и j занимают константный объем памяти.
Методы представления интервалов
Помимо описанного выше двойного замкнутого интервала, часто используется и левозамкнутый правооткрытый интервал, который задается как [0, n) , то есть левая граница включается, а правая - нет. В этом представлении интервал [i, j) пуст, когда i = j .
На основе этого представления можно реализовать двоичный поиск с той же функциональностью:
[file]{binary_search}-[class]{}-[func]{binary_search_lcro}
Как показано на рисунке ниже, в этих двух вариантах представления интервала различаются инициализация, условие цикла и операция сужения интервала в алгоритме двоичного поиска.
Поскольку в записи «двойной замкнутый интервал» обе границы являются закрытыми, операции сужения интервала при помощи указателей i и j тоже получаются симметричными. Из-за этого в таком варианте сложнее допустить ошибку, поэтому обычно рекомендуется использовать именно запись «двойной замкнутый интервал».
Преимущества и ограничения
Двоичный поиск показывает хорошие результаты и по времени, и по памяти.
- Двоичный поиск очень эффективен по времени. На больших объемах данных логарифмическая временная сложность дает заметное преимущество. Например, когда размер данных
n = 2^{20}, линейный поиск потребует2^{20} = 1048576итераций, тогда как двоичный поиск выполнится всего за\log_2 2^{20} = 20итераций. - Двоичный поиск не требует дополнительной памяти. По сравнению с алгоритмами поиска, которым нужно внешнее пространство (например, с хеш-поиском), двоичный поиск заметно экономнее по памяти.
Однако двоичный поиск подходит не для всех ситуаций, и основные причины таковы.
- Двоичный поиск применим только к упорядоченным данным. Если входные данные неупорядочены, специально сортировать их ради двоичного поиска невыгодно. Это связано с тем, что временная сложность алгоритмов сортировки обычно составляет
O(n \log n), что выше, чем у линейного и двоичного поиска. Если элементы приходится часто вставлять, то для сохранения порядка в массиве их нужно помещать в конкретные позиции, а это требуетO(n)времени и тоже обходится дорого. - Двоичный поиск применим только к массивам. Для него нужен скачкообразный доступ к элементам, а в связном списке такой доступ малоэффективен, поэтому двоичный поиск не подходит для списков и структур данных, построенных на их основе.
- При малом объеме данных линейный поиск работает лучше. В линейном поиске на каждом шаге нужна всего одна операция сравнения. В двоичном поиске требуется 1 сложение, 1 деление, от 1 до 3 сравнений и еще 1 сложение или вычитание, то есть всего от 4 до 6 элементарных операций. Поэтому при небольшом
nлинейный поиск может оказаться быстрее двоичного.








