pygorithm/search/binary_search.py

117 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
使用二分查找的前提是,查找的序列是已经排序过的,时间复杂度为 O(nlog2n)
1. 使用两个指针low, high分别指向第一个元素和最后一个元素
2. 取low 和 high 之间的中间值,并将此值与要查找的值比较
(2.1) 若小于查找值向右缩小范围low 移向中间high 不变
(2.2) 若大于查找值则向左缩小范围high 移向中间low 不变
3. 重复第2步
"""
def binary_search(sequence: list[int], value):
low = 0
high = len(sequence) - 1
mid = (low + high) // 2
while low != high:
if sequence[mid] > value:
high = mid - 1
elif sequence[mid] < value:
low = mid + 1
else:
return mid
mid = (low + high) // 2
if sequence[low] == value:
return low
else:
return False
def binary_search_recur(sequence, value, low, high):
if sequence[(low + high) // 2] == value:
return (low + high) // 2
if low == high:
return low if sequence[low] == value else False
if sequence[(low + high) // 2] > value:
return binary_search_recur(sequence, value, low, (low + high) // 2 - 1)
if sequence[(low + high) // 2] < value:
return binary_search_recur(sequence, value, (low + high) // 2 + 1, high)
"""
使用内插查找:时间复杂度为 O(loglog2n)
内插查找是一种二分查找的变形,适合在排序数据中进行查找。
内插查找不是像二分查找算法中那样直接使用中值来定界,而是通过插值算法找到上下
界。
类似于计算一条直线的函数: y=kx。在已排序的序列中取两点 [x0, y0], [x1, y1],即可计算出这两
点之间的任何值:(x-x0)/(y-y0) = (x0-x1)/(y0-y1) x=(y-y0)(x1-x0)/(y1-y0) + x0 => 直线斜率计算式
因此对于一个序列下标可作为x值为y
1. 取第一个元素的下表和值为 x0, y0最后的元素的下标和值为x1, y1
2. 将要查找的值作为 y, 通过斜率公式计算对应的 x
3. 取下标为 x 的值,若值大于 y将这个下标和值作为上界反之作为下界
4. 重复23
"""
def interpolation_search(sequence, value):
low = 0
high = len(sequence) - 1
while low < high:
x = (value - sequence[low]) * (high - low) // (sequence[high] - sequence[low]) + low
if sequence[low] > value:
return False
if sequence[x] > value:
high = x - 1
elif sequence[x] < value:
low = x + 1
else:
return x
if sequence[low] == value:
return low
else:
return False
"""
指数查找:它划分中值的方法不是使用平均或插值而是用指数函数来估计,这样可以快速找到上界
该算法适合已排序且无边界的数据。
算法查找过程中不断比较 2^0, 2^1, 2^2, 2^k 位置上的值和目标值的关系,进而确定搜索区域,之后在
该区域内使用二分查找算法查找
假设要在 [2,3,4,6,7,8,10,13,15,19,20,22,23,24,28] 这个 15 个元素已排序集合中查找 22
那么首先查看 2
0 = 1 位置上的数字是否超过 22得到 3 < 22所以继续查找 2^1, 2^2, 2^3 位置
处元素,发现对应的值 4, 7, 15 均小于 22。继续查看 16 = 24 处的值,可是 16 大于集合元
素个数,超出范围了,所以查找上界就是最后一个索引 14。
注意下界是 high 的一半,能找到一个上界,那么说明前一次访问处也就是 2^(n-1)
一定小于待查找的值,作为下界是合理的
"""
def exponential_search(sequence: list[int], value):
size = len(sequence)
# 由于下界取上界的一半,所以 high 从 1 开始
high = 1
while high < size and sequence[high] < value:
high <<= 1
low = high >> 1
res = binary_search(sequence[low: high + 1], value)
return res + low if res else res
sequence = [1, 4, 6, 10, 14, 18, 24, 39, 50]
num1 = 10
exponential_search(sequence, num1)