二分查找
原理
二分查找又叫折半查找,从有序列表的初始候选区li[0:n]
开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半。
如果待查值小于候选区中间值,则只需比较中间值左边的元素,减半查找范围。依次类推依次减半。
二分查找的前提:列表有序
二分查找的有点:查找速度快
二分查找的时间复杂度为:O(logn)
动画演示
代码实现
# 代码实现,假设列表元素升序排列
def binary_search(target, li):
left = 0
right = len(li) - 1
while left <= right:
mid = (left + right) // 2
if target == li[mid]: # 刚好找到
return mid
elif target < li[mid]: # 待查值在候选区的左半部分,调整候选区右边界,
right = mid - 1
else: # 待差值在候选区的右半部分,调整候选区左边界
left = mid + 1
else:
return -1
递归实现
使用函数递归调用也可以实现二分查找算法,但不推荐,递归调用本身就需要占用内存(栈区记录递归次数)
基础版:基础版只能判断出待查找的数是否在列表中,不能提供该值在列表中的索引值。
缺点:每次递归都要做列表切片,占用额外内存空间。
def binary_search(li, target):
# print(li)
if not li: # 此处使用if-else判断就相当于递归退出条件了
print('找不到')
else:
mid_index = len(li) // 2
# print(li[mid_index])
if target == li[mid_index]:
print('找到了')
elif target < li[mid_index]:
binary_search(li[:mid_index], target)
elif target > li[mid_index]:
binary_search(li[mid_index+1:], target)
if __name__ == '__main__':
li = [2,5,7,12,54,89,100]
binary_search(li, 80)
强化版:找到后返回其所在的索引值,找不到返回-1。
缺点:函数参数稍微复杂点。
def binary_search_plus(li, target, left, right):
"""
递归二分查找,找到返回索引值,找不到返回 -1
:param li: 待查找列表
:param target: 待查找目标值
:param left: 索引开始值,0
:param right: 索引结束值,len(li)-1
:return: index or -1
"""
# print(li[left:right+1])
if left > right:
return -1 # 找不到返回-1
mid = (left + right) // 2
# print(li[mid])
if target == li[mid]:
return mid # 找到返回索引值
elif target < li[mid]:
return binary_search_plus(li, target, left, mid-1)
elif target > li[mid]:
return binary_search_plus(li, target, mid+1, right)
if __name__ == '__main__':
li = [2,5,7,12,54,89,100]
res = binary_search(li, 80)
print(res)