Рассмотрите следующий фрагмент кода на Python и объясните, в чём логическая ошибка алгоритма бинарного поиска, какую временную сложность он имеет и как его исправить для корректной работы на массиве с повторяющимися элементами:
def binsearch(a, x):
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] == x:
return mid
if a[mid]

5 Ноя в 13:54
9 +9
0
Ответы
1
Кратко — ошибка в обновлении границ: при использовании полуоткрытого интервала [lo,hi)[lo,hi)[lo,hi) нельзя писать lo=midlo = midlo=mid или hi=midhi = midhi=mid, потому что при hi−lo=1hi-lo=1hilo=1 будет mid=lo\text{mid}=lomid=lo и присваивание lo=midlo=midlo=mid не сдвинет границу (зациклит). Временная сложность алгоритма при корректной реализации — O(log⁡n)O(\log n)O(logn).
Подробно и исправления:
1) Причина ошибки
- В цикле вычисляется mid=(lo+hi)//2\text{mid} = (lo+hi)//2mid=(lo+hi)//2. Если hi−lo=1hi-lo=1hilo=1, то mid=lo\text{mid}=lomid=lo. При ветке a[mid]<xa[\text{mid}]<xa[mid]<x код делает lo=midlo=\text{mid}lo=mid, границы не меняются и цикл бесконечен. Пример: hi−lo=1hi-lo=1hilo=1 (разрыв один элемент) — нет прогресса.
2) Правильный простой фикс (вернёт любой индекс с совпадением)
- Для полуоткрытого интервала [lo,hi)[lo,hi)[lo,hi) обновления должны быть:
- если a[mid]<xa[\text{mid}]<xa[mid]<x: lo=mid+1lo=\text{mid}+1lo=mid+1 - если a[mid]>xa[\text{mid}]>xa[mid]>x: hi=midhi=\text{mid}hi=mid - если равно — можно вернуть mid\text{mid}mid - Тогда гарантированно происходит сужение интервала и сложность O(log⁡n)O(\log n)O(logn).
Пример исправленного кода (любая найденная позиция):
def binsearch(a, x):
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] == x:
return mid
if a[mid] < x:
lo = mid + 1
else:
hi = mid
return -1
3) Если нужен левый (первый) индекс при повторяющихся элементах
- Использовать поиск границы: сужаем так, чтобы в конце lololo был индекс первой позиции ≥x\ge xx. После цикла проверяем равенство.
Код для левого вхождения:
def bisect_left(a, x):
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < x:
lo = mid + 1
else:
hi = mid
return lo if lo < len(a) and a[lo] == x else -1
Аналогично для правого вхождения можно настраивать условия.
5 Ноя в 14:20
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир