63 KiB
comments
| comments |
|---|
| true |
10.1 Двоичный поиск
Двоичный поиск (binary search) - это эффективный алгоритм поиска, основанный на стратегии «разделяй и властвуй». Он использует упорядоченность данных, сокращая на каждом шаге область поиска вдвое, пока не будет найден целевой элемент или пока интервал поиска не опустеет.
!!! question
Дан массив `nums` длины $n$, элементы которого расположены в порядке возрастания и не повторяются. Найдите и верните индекс элемента `target` в этом массиве. Если массив не содержит этого элемента, верните $-1$ . Пример показан на рисунке 10-1.
Рисунок 10-1 Пример данных для двоичного поиска
Как показано на рисунке 10-2, сначала инициализируем указатели 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 .
=== "<1>"
{ class="animation-figure" }
=== "<2>"
{ class="animation-figure" }
=== "<3>"
{ class="animation-figure" }
=== "<4>"
{ class="animation-figure" }
=== "<5>"
{ class="animation-figure" }
=== "<6>"
{ class="animation-figure" }
=== "<7>"
{ class="animation-figure" }
Рисунок 10-2 Процесс двоичного поиска
Стоит отметить, что поскольку и i , и j имеют тип int , то сумма i + j может выйти за пределы диапазона типа int. Чтобы избежать переполнения, обычно используют формулу m = \lfloor {i + (j - i) / 2} \rfloor для вычисления середины.
Код приведен ниже:
=== "Python"
```python title="binary_search.py"
def binary_search(nums: list[int], target: int) -> int:
"""Бинарный поиск (двусторонне замкнутый интервал)"""
# Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
i, j = 0, len(nums) - 1
# Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while i <= j:
# Теоретически числа в Python могут быть сколь угодно большими (ограничены только объемом памяти), поэтому не нужно учитывать переполнение больших чисел
m = (i + j) // 2 # Вычислить индекс середины m
if nums[m] < target:
i = m + 1 # Это означает, что target находится в интервале [m+1, j]
elif nums[m] > target:
j = m - 1 # Это означает, что target находится в интервале [i, m-1]
else:
return m # Целевой элемент найден, вернуть его индекс
return -1 # Целевой элемент не найден, вернуть -1
```
=== "C++"
```cpp title="binary_search.cpp"
/* Бинарный поиск (двусторонне замкнутый интервал) */
int binarySearch(vector<int> &nums, int target) {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
int i = 0, j = nums.size() - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j]
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m-1]
j = m - 1;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Java"
```java title="binary_search.java"
/* Бинарный поиск (двусторонне замкнутый интервал) */
int binarySearch(int[] nums, int target) {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
int i = 0, j = nums.length - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j]
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m-1]
j = m - 1;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "C#"
```csharp title="binary_search.cs"
/* Бинарный поиск (двусторонне замкнутый интервал) */
int BinarySearch(int[] nums, int target) {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
int i = 0, j = nums.Length - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j]
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m-1]
j = m - 1;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Go"
```go title="binary_search.go"
/* Бинарный поиск (двусторонне замкнутый интервал) */
func binarySearch(nums []int, target int) int {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
i, j := 0, len(nums)-1
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
for i <= j {
m := i + (j-i)/2 // Вычислить индекс середины m
if nums[m] < target { // Это означает, что target находится в интервале [m+1, j]
i = m + 1
} else if nums[m] > target { // Это означает, что target находится в интервале [i, m-1]
j = m - 1
} else { // Целевой элемент найден, вернуть его индекс
return m
}
}
// Целевой элемент не найден, вернуть -1
return -1
}
```
=== "Swift"
```swift title="binary_search.swift"
/* Бинарный поиск (двусторонне замкнутый интервал) */
func binarySearch(nums: [Int], target: Int) -> Int {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
var i = nums.startIndex
var j = nums.endIndex - 1
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while i <= j {
let m = i + (j - i) / 2 // Вычислить индекс середины m
if nums[m] < target { // Это означает, что target находится в интервале [m+1, j]
i = m + 1
} else if nums[m] > target { // Это означает, что target находится в интервале [i, m-1]
j = m - 1
} else { // Целевой элемент найден, вернуть его индекс
return m
}
}
// Целевой элемент не найден, вернуть -1
return -1
}
```
=== "JS"
```javascript title="binary_search.js"
/* Бинарный поиск (двусторонне замкнутый интервал) */
function binarySearch(nums, target) {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
let i = 0,
j = nums.length - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
// Вычислить индекс середины m, используя parseInt() для округления вниз
const m = parseInt(i + (j - i) / 2);
if (nums[m] < target)
// Это означает, что target находится в интервале [m+1, j]
i = m + 1;
else if (nums[m] > target)
// Это означает, что target находится в интервале [i, m-1]
j = m - 1;
else return m; // Целевой элемент найден, вернуть его индекс
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "TS"
```typescript title="binary_search.ts"
/* Бинарный поиск (двусторонне замкнутый интервал) */
function binarySearch(nums: number[], target: number): number {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
let i = 0,
j = nums.length - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
// Вычислить индекс середины m
const m = Math.floor(i + (j - i) / 2);
if (nums[m] < target) {
// Это означает, что target находится в интервале [m+1, j]
i = m + 1;
} else if (nums[m] > target) {
// Это означает, что target находится в интервале [i, m-1]
j = m - 1;
} else {
// Целевой элемент найден, вернуть его индекс
return m;
}
}
return -1; // Целевой элемент не найден, вернуть -1
}
```
=== "Dart"
```dart title="binary_search.dart"
/* Бинарный поиск (двусторонне замкнутый интервал) */
int binarySearch(List<int> nums, int target) {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
int i = 0, j = nums.length - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
int m = i + (j - i) ~/ 2; // Вычислить индекс середины m
if (nums[m] < target) {
// Это означает, что target находится в интервале [m+1, j]
i = m + 1;
} else if (nums[m] > target) {
// Это означает, что target находится в интервале [i, m-1]
j = m - 1;
} else {
// Целевой элемент найден, вернуть его индекс
return m;
}
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Rust"
```rust title="binary_search.rs"
/* Бинарный поиск (двусторонне замкнутый интервал) */
fn binary_search(nums: &[i32], target: i32) -> i32 {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
let mut i = 0;
let mut j = nums.len() as i32 - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while i <= j {
let m = i + (j - i) / 2; // Вычислить индекс середины m
if nums[m as usize] < target {
// Это означает, что target находится в интервале [m+1, j]
i = m + 1;
} else if nums[m as usize] > target {
// Это означает, что target находится в интервале [i, m-1]
j = m - 1;
} else {
// Целевой элемент найден, вернуть его индекс
return m;
}
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "C"
```c title="binary_search.c"
/* Бинарный поиск (двусторонне замкнутый интервал) */
int binarySearch(int *nums, int len, int target) {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
int i = 0, j = len - 1;
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j]
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m-1]
j = m - 1;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Kotlin"
```kotlin title="binary_search.kt"
/* Бинарный поиск (двусторонне замкнутый интервал) */
fun binarySearch(nums: IntArray, target: Int): Int {
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
var i = 0
var j = nums.size - 1
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while (i <= j) {
val m = i + (j - i) / 2 // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j]
i = m + 1
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m-1]
j = m - 1
else // Целевой элемент найден, вернуть его индекс
return m
}
// Целевой элемент не найден, вернуть -1
return -1
}
```
=== "Ruby"
```ruby title="binary_search.rb"
### Бинарный поиск (двусторонне замкнутый интервал) ###
def binary_search(nums, target)
# Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
i, j = 0, nums.length - 1
# Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
while i <= j
# Теоретически числа в Ruby могут быть сколь угодно большими (ограничены только объемом памяти), поэтому не нужно учитывать переполнение больших чисел
m = (i + j) / 2 # Вычислить индекс середины m
if nums[m] < target
i = m + 1 # Это означает, что target находится в интервале [m+1, j]
elsif nums[m] > target
j = m - 1 # Это означает, что target находится в интервале [i, m-1]
else
return m # Целевой элемент найден, вернуть его индекс
end
end
-1 # Целевой элемент не найден, вернуть -1
end
```
??? pythontutor "Визуализация кода"
<div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20binary_search%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%B4%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B5%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%22%22%22%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%B4%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B5%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%20%5B0%2C%20n-1%5D%2C%20%D1%82%D0%BE%20%D0%B5%D1%81%D1%82%D1%8C%20i%20%D0%B8%20j%20%D1%83%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%82%20%D0%BD%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B2%D1%8B%D0%B9%20%D0%B8%20%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BD%D0%B8%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D1%8B%20%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0%20%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%20-%201%0A%20%20%20%20%23%20%D0%A6%D0%B8%D0%BA%D0%BB%20%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B0%D0%B5%D1%82%D1%81%D1%8F%2C%20%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0%20%D0%BF%D1%83%D1%81%D1%82%20%28%D0%BF%D1%80%D0%B8%20i%20%3E%20j%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D1%83%D1%81%D1%82%29%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%D0%A2%D0%B5%D0%BE%D1%80%D0%B5%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%20%D1%87%D0%B8%D1%81%D0%BB%D0%B0%20%D0%B2%20Python%20%D0%BC%D0%BE%D0%B3%D1%83%D1%82%20%D0%B1%D1%8B%D1%82%D1%8C%20%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%20%D1%83%D0%B3%D0%BE%D0%B4%D0%BD%D0%BE%20%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B8%D0%BC%D0%B8%20%28%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D1%8B%20%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE%20%D0%BE%D0%B1%D1%8A%D0%B5%D0%BC%D0%BE%D0%BC%20%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8%29%2C%20%D0%BF%D0%BE%D1%8D%D1%82%D0%BE%D0%BC%D1%83%20%D0%BD%D0%B5%20%D0%BD%D1%83%D0%B6%D0%BD%D0%BE%20%D1%83%D1%87%D0%B8%D1%82%D1%8B%D0%B2%D0%B0%D1%82%D1%8C%20%D0%BF%D0%B5%D1%80%D0%B5%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B8%D1%85%20%D1%87%D0%B8%D1%81%D0%B5%D0%BB%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D1%82%D1%8C%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%81%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%D0%BD%D1%8B%20m%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bm%2B1%2C%20j%5D%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bi%2C%20m-1%5D%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20%D0%B5%D0%B3%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%0A%20%20%20%20return%20-1%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B5%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%0A%20%20%20%20%23%20%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%B4%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B5%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%0A%20%20%20%20index%20%3D%20binary_search%28nums%2C%20target%29%0A%20%20%20%20print%28%22%D0%98%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%86%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B3%D0%BE%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%206%20%3D%20%22%2C%20index%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20binary_search%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%B4%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B5%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%22%22%22%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%B4%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B5%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%20%5B0%2C%20n-1%5D%2C%20%D1%82%D0%BE%20%D0%B5%D1%81%D1%82%D1%8C%20i%20%D0%B8%20j%20%D1%83%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%82%20%D0%BD%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B2%D1%8B%D0%B9%20%D0%B8%20%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BD%D0%B8%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D1%8B%20%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0%20%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%20-%201%0A%20%20%20%20%23%20%D0%A6%D0%B8%D0%BA%D0%BB%20%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B0%D0%B5%D1%82%D1%81%D1%8F%2C%20%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0%20%D0%BF%D1%83%D1%81%D1%82%20%28%D0%BF%D1%80%D0%B8%20i%20%3E%20j%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D1%83%D1%81%D1%82%29%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%D0%A2%D0%B5%D0%BE%D1%80%D0%B5%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%20%D1%87%D0%B8%D1%81%D0%BB%D0%B0%20%D0%B2%20Python%20%D0%BC%D0%BE%D0%B3%D1%83%D1%82%20%D0%B1%D1%8B%D1%82%D1%8C%20%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%20%D1%83%D0%B3%D0%BE%D0%B4%D0%BD%D0%BE%20%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B8%D0%BC%D0%B8%20%28%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D1%8B%20%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE%20%D0%BE%D0%B1%D1%8A%D0%B5%D0%BC%D0%BE%D0%BC%20%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8%29%2C%20%D0%BF%D0%BE%D1%8D%D1%82%D0%BE%D0%BC%D1%83%20%D0%BD%D0%B5%20%D0%BD%D1%83%D0%B6%D0%BD%D0%BE%20%D1%83%D1%87%D0%B8%D1%82%D1%8B%D0%B2%D0%B0%D1%82%D1%8C%20%D0%BF%D0%B5%D1%80%D0%B5%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B8%D1%85%20%D1%87%D0%B8%D1%81%D0%B5%D0%BB%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D1%82%D1%8C%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%81%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%D0%BD%D1%8B%20m%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bm%2B1%2C%20j%5D%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bi%2C%20m-1%5D%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20%D0%B5%D0%B3%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%0A%20%20%20%20return%20-1%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B5%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%0A%20%20%20%20%23%20%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%B4%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D0%B5%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%0A%20%20%20%20index%20%3D%20binary_search%28nums%2C%20target%29%0A%20%20%20%20print%28%22%D0%98%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%86%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B3%D0%BE%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%206%20%3D%20%22%2C%20index%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Во весь экран ></a></div>
Временная сложность равна $O(\log n)$ : в цикле двоичного поиска интервал каждый раз сокращается вдвое, поэтому число итераций равно \log_2 n .
Пространственная сложность равна $O(1)$ : указатели i и j занимают константный объем памяти.
10.1.1 Методы представления интервалов
Помимо описанного выше двойного замкнутого интервала, часто используется и левозамкнутый правооткрытый интервал, который задается как [0, n) , то есть левая граница включается, а правая - нет. В этом представлении интервал [i, j) пуст, когда i = j .
На основе этого представления можно реализовать двоичный поиск с той же функциональностью:
=== "Python"
```python title="binary_search.py"
def binary_search_lcro(nums: list[int], target: int) -> int:
"""Бинарный поиск (лево замкнутый, право открытый интервал)"""
# Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
i, j = 0, len(nums)
# Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while i < j:
m = (i + j) // 2 # Вычислить индекс середины m
if nums[m] < target:
i = m + 1 # Это означает, что target находится в интервале [m+1, j)
elif nums[m] > target:
j = m # Это означает, что target находится в интервале [i, m)
else:
return m # Целевой элемент найден, вернуть его индекс
return -1 # Целевой элемент не найден, вернуть -1
```
=== "C++"
```cpp title="binary_search.cpp"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
int binarySearchLCRO(vector<int> &nums, int target) {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
int i = 0, j = nums.size();
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j)
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m)
j = m;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Java"
```java title="binary_search.java"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
int binarySearchLCRO(int[] nums, int target) {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
int i = 0, j = nums.length;
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j)
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m)
j = m;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "C#"
```csharp title="binary_search.cs"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
int BinarySearchLCRO(int[] nums, int target) {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
int i = 0, j = nums.Length;
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j)
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m)
j = m;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Go"
```go title="binary_search.go"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
func binarySearchLCRO(nums []int, target int) int {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
i, j := 0, len(nums)
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
for i < j {
m := i + (j-i)/2 // Вычислить индекс середины m
if nums[m] < target { // Это означает, что target находится в интервале [m+1, j)
i = m + 1
} else if nums[m] > target { // Это означает, что target находится в интервале [i, m)
j = m
} else { // Целевой элемент найден, вернуть его индекс
return m
}
}
// Целевой элемент не найден, вернуть -1
return -1
}
```
=== "Swift"
```swift title="binary_search.swift"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
func binarySearchLCRO(nums: [Int], target: Int) -> Int {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
var i = nums.startIndex
var j = nums.endIndex
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while i < j {
let m = i + (j - i) / 2 // Вычислить индекс середины m
if nums[m] < target { // Это означает, что target находится в интервале [m+1, j)
i = m + 1
} else if nums[m] > target { // Это означает, что target находится в интервале [i, m)
j = m
} else { // Целевой элемент найден, вернуть его индекс
return m
}
}
// Целевой элемент не найден, вернуть -1
return -1
}
```
=== "JS"
```javascript title="binary_search.js"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
function binarySearchLCRO(nums, target) {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
let i = 0,
j = nums.length;
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
// Вычислить индекс середины m, используя parseInt() для округления вниз
const m = parseInt(i + (j - i) / 2);
if (nums[m] < target)
// Это означает, что target находится в интервале [m+1, j)
i = m + 1;
else if (nums[m] > target)
// Это означает, что target находится в интервале [i, m)
j = m;
// Целевой элемент найден, вернуть его индекс
else return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "TS"
```typescript title="binary_search.ts"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
function binarySearchLCRO(nums: number[], target: number): number {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
let i = 0,
j = nums.length;
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
// Вычислить индекс середины m
const m = Math.floor(i + (j - i) / 2);
if (nums[m] < target) {
// Это означает, что target находится в интервале [m+1, j)
i = m + 1;
} else if (nums[m] > target) {
// Это означает, что target находится в интервале [i, m)
j = m;
} else {
// Целевой элемент найден, вернуть его индекс
return m;
}
}
return -1; // Целевой элемент не найден, вернуть -1
}
```
=== "Dart"
```dart title="binary_search.dart"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
int binarySearchLCRO(List<int> nums, int target) {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
int i = 0, j = nums.length;
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
int m = i + (j - i) ~/ 2; // Вычислить индекс середины m
if (nums[m] < target) {
// Это означает, что target находится в интервале [m+1, j)
i = m + 1;
} else if (nums[m] > target) {
// Это означает, что target находится в интервале [i, m)
j = m;
} else {
// Целевой элемент найден, вернуть его индекс
return m;
}
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Rust"
```rust title="binary_search.rs"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
fn binary_search_lcro(nums: &[i32], target: i32) -> i32 {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
let mut i = 0;
let mut j = nums.len() as i32;
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while i < j {
let m = i + (j - i) / 2; // Вычислить индекс середины m
if nums[m as usize] < target {
// Это означает, что target находится в интервале [m+1, j)
i = m + 1;
} else if nums[m as usize] > target {
// Это означает, что target находится в интервале [i, m)
j = m;
} else {
// Целевой элемент найден, вернуть его индекс
return m;
}
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "C"
```c title="binary_search.c"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
int binarySearchLCRO(int *nums, int len, int target) {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
int i = 0, j = len;
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
int m = i + (j - i) / 2; // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j)
i = m + 1;
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m)
j = m;
else // Целевой элемент найден, вернуть его индекс
return m;
}
// Целевой элемент не найден, вернуть -1
return -1;
}
```
=== "Kotlin"
```kotlin title="binary_search.kt"
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
fun binarySearchLCRO(nums: IntArray, target: Int): Int {
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
var i = 0
var j = nums.size
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while (i < j) {
val m = i + (j - i) / 2 // Вычислить индекс середины m
if (nums[m] < target) // Это означает, что target находится в интервале [m+1, j)
i = m + 1
else if (nums[m] > target) // Это означает, что target находится в интервале [i, m)
j = m
else // Целевой элемент найден, вернуть его индекс
return m
}
// Целевой элемент не найден, вернуть -1
return -1
}
```
=== "Ruby"
```ruby title="binary_search.rb"
### Бинарный поиск (лево замкнутый, право открытый интервал) ###
def binary_search_lcro(nums, target)
# Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
i, j = 0, nums.length
# Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
while i < j
# Вычислить индекс середины m
m = (i + j) / 2
if nums[m] < target
i = m + 1 # Это означает, что target находится в интервале [m+1, j)
elsif nums[m] > target
j = m - 1 # Это означает, что target находится в интервале [i, m)
else
return m # Целевой элемент найден, вернуть его индекс
end
end
-1 # Целевой элемент не найден, вернуть -1
end
```
??? pythontutor "Визуализация кода"
<div style="height: 549px; width: 100%;"><iframe class="pythontutor-iframe" src="https://pythontutor.com/iframe-embed.html#code=def%20binary_search_lcro%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%BB%D0%B5%D0%B2%D0%BE%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%2C%20%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%20%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%22%22%22%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%BB%D0%B5%D0%B2%D0%BE%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%2C%20%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%20%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%20%5B0%2C%20n%29%2C%20%D1%82%D0%BE%20%D0%B5%D1%81%D1%82%D1%8C%20i%20%D0%B8%20j%20%D1%83%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%82%20%D0%BD%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B2%D1%8B%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0%20%D0%B8%20%D0%BF%D0%BE%D0%B7%D0%B8%D1%86%D0%B8%D1%8E%20%D1%81%D1%80%D0%B0%D0%B7%D1%83%20%D0%B7%D0%B0%20%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BD%D0%B8%D0%BC%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%BC%20%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%0A%20%20%20%20%23%20%D0%A6%D0%B8%D0%BA%D0%BB%20%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B0%D0%B5%D1%82%D1%81%D1%8F%2C%20%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0%20%D0%BF%D1%83%D1%81%D1%82%20%28%D0%BF%D1%80%D0%B8%20i%20%3D%20j%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D1%83%D1%81%D1%82%29%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D1%82%D1%8C%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%81%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%D0%BD%D1%8B%20m%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bm%2B1%2C%20j%29%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bi%2C%20m%29%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20%D0%B5%D0%B3%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%0A%20%20%20%20return%20-1%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B5%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%0A%20%20%20%20%23%20%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%BB%D0%B5%D0%B2%D0%BE%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%2C%20%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%20%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%0A%20%20%20%20index%20%3D%20binary_search_lcro%28nums%2C%20target%29%0A%20%20%20%20print%28%22%D0%98%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%86%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B3%D0%BE%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%206%20%3D%20%22%2C%20index%29&codeDivHeight=472&codeDivWidth=350&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false"> </iframe></div>
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=def%20binary_search_lcro%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%BB%D0%B5%D0%B2%D0%BE%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%2C%20%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%20%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%22%22%22%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%BB%D0%B5%D0%B2%D0%BE%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%2C%20%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%20%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%20%5B0%2C%20n%29%2C%20%D1%82%D0%BE%20%D0%B5%D1%81%D1%82%D1%8C%20i%20%D0%B8%20j%20%D1%83%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%8E%D1%82%20%D0%BD%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B2%D1%8B%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0%20%D0%B8%20%D0%BF%D0%BE%D0%B7%D0%B8%D1%86%D0%B8%D1%8E%20%D1%81%D1%80%D0%B0%D0%B7%D1%83%20%D0%B7%D0%B0%20%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BD%D0%B8%D0%BC%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%BC%20%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%0A%20%20%20%20%23%20%D0%A6%D0%B8%D0%BA%D0%BB%20%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B0%D0%B5%D1%82%D1%81%D1%8F%2C%20%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0%20%D0%BF%D1%83%D1%81%D1%82%20%28%D0%BF%D1%80%D0%B8%20i%20%3D%20j%20%D0%B4%D0%B8%D0%B0%D0%BF%D0%B0%D0%B7%D0%BE%D0%BD%20%D0%BF%D1%83%D1%81%D1%82%29%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%D0%92%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D1%82%D1%8C%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%81%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%D0%BD%D1%8B%20m%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bm%2B1%2C%20j%29%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20%20%23%20%D0%AD%D1%82%D0%BE%20%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B0%D0%B5%D1%82%2C%20%D1%87%D1%82%D0%BE%20target%20%D0%BD%D0%B0%D1%85%D0%BE%D0%B4%D0%B8%D1%82%D1%81%D1%8F%20%D0%B2%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%B5%20%5Bi%2C%20m%29%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20%D0%B5%D0%B3%D0%BE%20%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%0A%20%20%20%20return%20-1%20%20%23%20%D0%A6%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%BD%D0%B5%20%D0%BD%D0%B0%D0%B9%D0%B4%D0%B5%D0%BD%2C%20%D0%B2%D0%B5%D1%80%D0%BD%D1%83%D1%82%D1%8C%20-1%0A%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%0A%20%20%20%20%23%20%D0%91%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%20%28%D0%BB%D0%B5%D0%B2%D0%BE%20%D0%B7%D0%B0%D0%BC%D0%BA%D0%BD%D1%83%D1%82%D1%8B%D0%B9%2C%20%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%20%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%B9%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%29%0A%20%20%20%20index%20%3D%20binary_search_lcro%28nums%2C%20target%29%0A%20%20%20%20print%28%22%D0%98%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%20%D1%86%D0%B5%D0%BB%D0%B5%D0%B2%D0%BE%D0%B3%D0%BE%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%206%20%3D%20%22%2C%20index%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=5&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Во весь экран ></a></div>
Как показано на рисунке 10-3, в этих двух вариантах представления интервала различаются инициализация, условие цикла и операция сужения интервала в алгоритме двоичного поиска.
Поскольку в записи «двойной замкнутый интервал» обе границы являются закрытыми, операции сужения интервала при помощи указателей i и j тоже получаются симметричными. Из-за этого в таком варианте сложнее допустить ошибку, поэтому обычно рекомендуется использовать именно запись «двойной замкнутый интервал».
Рисунок 10-3 Два определения интервалов
10.1.2 Преимущества и ограничения
Двоичный поиск показывает хорошие результаты и по времени, и по памяти.
- Двоичный поиск очень эффективен по времени. На больших объемах данных логарифмическая временная сложность дает заметное преимущество. Например, когда размер данных
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линейный поиск может оказаться быстрее двоичного.

