Files
hello-algo/ru/docs/chapter_searching/binary_search.md
T
krahets e53a7f2498 build
2026-04-14 18:06:14 +08:00

63 KiB

comments
comments
true

10.1   Двоичный поиск

Двоичный поиск (binary search) - это эффективный алгоритм поиска, основанный на стратегии «разделяй и властвуй». Он использует упорядоченность данных, сокращая на каждом шаге область поиска вдвое, пока не будет найден целевой элемент или пока интервал поиска не опустеет.

!!! question

Дан массив `nums` длины $n$, элементы которого расположены в порядке возрастания и не повторяются. Найдите и верните индекс элемента `target` в этом массиве. Если массив не содержит этого элемента, верните $-1$ . Пример показан на рисунке 10-1.

Пример данных для двоичного поиска{ class="animation-figure" }

Рисунок 10-1   Пример данных для двоичного поиска

Как показано на рисунке 10-2, сначала инициализируем указатели i = 0 и j = n - 1 , которые указывают на первый и последний элементы массива и задают интервал поиска [0, n - 1] . Обратите внимание: квадратные скобки обозначают замкнутый интервал и включают граничные значения.

Далее в цикле выполняются следующие два шага.

  1. Вычислить индекс середины m = \lfloor {(i + j) / 2} \rfloor , где \lfloor \: \rfloor означает операцию округления вниз.
  2. Сравнить nums[m] и target , после чего возможны три случая.
    1. Если nums[m] < target , это означает, что target находится в интервале [m + 1, j] , поэтому выполняется i = m + 1 .
    2. Если nums[m] > target , это означает, что target находится в интервале [i, m - 1] , поэтому выполняется j = m - 1 .
    3. Если nums[m] = target , значит, элемент target найден, поэтому возвращается индекс m .

Если массив не содержит целевой элемент, область поиска в итоге сузится до пустого интервала. В этом случае возвращается -1 .

=== "<1>" Процесс двоичного поиска{ class="animation-figure" }

=== "<2>" binary_search_step2{ class="animation-figure" }

=== "<3>" binary_search_step3{ class="animation-figure" }

=== "<4>" binary_search_step4{ class="animation-figure" }

=== "<5>" binary_search_step5{ class="animation-figure" }

=== "<6>" binary_search_step6{ class="animation-figure" }

=== "<7>" binary_search_step7{ 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 тоже получаются симметричными. Из-за этого в таком варианте сложнее допустить ошибку, поэтому обычно рекомендуется использовать именно запись «двойной замкнутый интервал».

Два определения интервалов{ class="animation-figure" }

Рисунок 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 линейный поиск может оказаться быстрее двоичного.