标签:次数 范围 list arch span 假设 长度 python 一个
二分查找(Binary Search)法,是在一个有序的集合中查找指定键值的一种方法。假设有一个集合,集合中的元素按照键值从小到大有序。集合中元素的键可以用一个列表 \(list = (x_1, x_2, ..., x_n)\)表示,其中\(x_i \leq x_{i+1}\)。任务是要查找一个键\(key\)在这个列表中的位置。
例如,\(list=(-5, 4, 8, 9, 19, 81, 195, 803)\),要查找 \(9\)是列表中的第几个数。
如果\(key\)在列表中,则报告\(key\)的位置,否则报告查找失败。如果\(key\)在列表中多次出现(必定相邻),则返回其中任意一次出现的位置。
二分查找法也叫折半查找法,该方法首先比较\(key\)和列表正中间位置\(mid\)对应元素的键,若\(key\)与\(mid\)位置的元素相等,则返回\(mid\)。若\(key\)大于\(mid\)位置的元素,则在列表的右半段子列表中继续查找,否则在列表的左半段中继续查找,直到子列表的长度为0。
假设列表用\(L\)表示,其长度为\(N\),该方法可以概括如下:
二分查找法采用的是分治策略,不算地缩小解的搜索空间,可以用递归的方式实现,也可以用循环的方式实现。
如果采用递归的方式实现,递归的基线条件是待搜索的序列长度为0。每一次递归中,比较序列中间元素与键的差别,根据比较结果,相等则返回,否则在递归地在子序列中继续搜索。
def binary_search_r(lst, key, low=0, high=None):
"""
在有序列表lst中查找key,递归实现
@lst: 有序列表
@key: 查找的键
"""
if high is None:
high = len(lst)
if low >= high: # 基线条件
return None
mid = (low + high) // 2
if key == lst[mid]: # 查找成功
return mid
elif key < lst[mid]:
high = mid # 左子序列递归查找
return binary_search_r(lst, key, low, high)
else:
low = mid + 1 # 右子序列查找
return binary_search_r(lst, key, low, high)
如果采用循环实现,则在循环中记录当前查找的\(low\),\(high\)两个位置,根据序列中间元素与键的大小比较结果,要么查找成功,要么改变\(low\)或\(high\)的值,直到\(low \geq high\)。
def binary_search(lst, key):
"""
在有序列表lst中查找key,循环实现
@lst: 有序列表
@key: 查找的键
"""
low = 0
high = len(lst)
while low < high:
mid = (low + high) // 2
if key == lst[mid]:
return mid
elif key < lst[mid]:
high = mid
else:
low = mid + 1
return None
下面是简单的测试代码:
if __name__ == "__main__":
x = [3, 5, 6, 7, 9, 100, 107]
for ax in x:
print(ax, binary_search_r(x, ax), binary_search(x, ax))
for ax in [-5, -1, 0, 10, 105, 123]:
print(ax, binary_search_r(x, ax), binary_search(x, ax))
正确性
二分查找的每一次迭代中,都将查找范围限定为 \(low\)和\(high\)之间,也就是认为\(key\)如果存在在\(L\)中,则必定有\(L[low] \leq key < L[high]\)。所以要算法正确,只要这个命题成立: 若\(key \in L\),那么在每一次迭代中,\(L[low] \leq key < L[high]\)必然成立。
在第\(k+1\)步,\(mid = \lfloor (low_k + high_k) / 2 \rfloor\):
时间复杂度
最差情况下,键不在列表中,但是二分查找直到最后子序列长度为0才停止。假设原序列长度为\(N\),每轮迭代将范围缩小一半。第一轮迭代后,待查序列长度为\(N/2\),第二轮迭代后,待查序列长度为 \(N/2^2\)。设最大迭代次数为\(k\),则\(N/2^{k-1} >1, N/2^{k} \leq 1\),即\(k = \lceil \log_2 N \rceil\)。因此,对于长度为\(N\)的表,二分查找的最大迭代次数时\(\log_2 N\),算法复杂度为 \(O(\log_2N)\)。
标签:次数 范围 list arch span 假设 长度 python 一个
原文地址:https://www.cnblogs.com/data_algorithms/p/binary_search.html