二分查找针对有序集合,每次查找通过跟中间元素对比大小,将待查找的区间缩小为原来的一半,直到找到要查找的元素或者区间缩小为0.
二分查找是一种时间复杂度为O(logN)的查找算法,有时甚至比 hash 表中的 O(1)算法效率还要高,因为 hash 表计算 hash 值、解决冲突所花的时间不一定比 O(logN)短。
二分查找依赖的是顺序表结构,简单的说就是数组,利用数组支持按下标访问的特性实现高速查找。
二分查找使用场景:
既然二分查找依赖的是有序数组,所以先将数据排序,常见的快速排序如下:
def qsort(arr):
qsort_p(arr, 0, len(arr)-1)
def qsort_p(arr, p, q):
if p < q:
pivot = arr[q]
i = p
for j in range(p, q):
if arr[j] < pivot:
arr[i], arr[j] = arr[j], arr[i]
i += 1
arr[i], arr[q] = arr[q], arr[i]
qsort(arr, p, i-1)
qsort(arr, i+1, q)
for 循环借助插入排序的思想,变量 i 将数据一分为二:已处理区间和未处理区间,每次从 i..q-1 中取出一个元素arr[j]与 pivot 对比,如果小于 pivot 则将此数据放到已处理区间的末尾也就是 arr[i] 的位置。循环完成将 arr[i] 与 pivot 值互换,arr[i] 左边就是小于 pivot 的,右边是大于 pivot 的数据。
代码实现:
def bsearch(arr, val):
low, high = 0, len(arr) - 1
while low <= high:
mid = low + (high - low) // 2
if arr[mid] > val:
high = mid - 1
elif arr[mid] < val:
low = mid + 1
else:
return mid
return -1
每次都与区间中间值 arr[mid] 比较,缩小比较范围。若大于 arr[mid] 则更新 low = mid + 1;若小于 arr[mid] 则更新 high = mid - 1
精确到小数点后6位
def bsqrt(n):
low, high = 0, n
while high - low > 0.000001:
mid = low + (high - low) / 2
if mid * mid > n:
high = mid
elif mid * mid < n:
low = mid
else:
return mid
return mid
在数组中下标是整数,所以用了 (high - low) // 2,而这里直接使用的小数乘法,所以是正常的除法
在找到给定值后不停下,而是继续往 前 查找,直到 mid 为 0 或者 mid 的前一个值不等于 val
def first_equal(arr, val):
low, high = 0, len(arr) - 1
while low <= high:
mid = low + (high - low) // 2
if arr[mid] < val:
low = mid + 1
elif arr[mid] > val:
high = mid - 1
else:
if mid == 0 or arr[mid-1] != val:
return mid
else:
high = mid - 1
return -1
在找到给定值后不停下,而是继续往 后 查找,直到 mid 为 len(arr) - 1 或者 mid 的后一个值不等于 val
def last_equal(arr, val):
length = len(arr)
low, high = 0, length - 1
while low <= high:
mid = low + (high - low) // 2
if arr[mid] > val:
high = mid - 1
elif arr[mid] < val:
low = mid + 1
else:
if mid == length - 1 or arr[mid+1] != val:
return mid
else:
low = mid + 1
return -1
一直往 前 查找,直到 mid 为 0 或者 mid 的前一个值小于 val
def first_great(arr, val):
length = len(arr)
low, high = 0, length - 1
while low <= high:
mid = low + (high - low) // 2
if arr[mid] < val:
low = mid + 1
else:
if mid == 0 or arr[mid-1] < val:
return mid
high = mid - 1
return -1
一直往 后 查找,直到 mid 为 len(arr)-1 或者 mid 的后一个值大于 val
def last_less(arr, val):
length = len(arr)
low, high = 0, length - 1
while low <= high:
mid = low + (high - low) // 2
if arr[mid] <= val:
if mid == length - 1 or arr[mid+1] > val:
return mid
else:
low = mid + 1
else:
high = mid - 1
return -1
原文:https://www.cnblogs.com/wbjxxzx/p/12243150.html