二分法查找是一种十分高效的方法,可以在极少的步数之内查找到我们需要的内容。这种方法在我们日常生活中随处可见,你可能在熟练地运用这种方法,但是你却没有意识到他的存在罢了。我们先讲几个简单的例子,来说明一下什么是二分法:
小学时,人手一本新华字典。当你去查找 “馄饨” 的读音时,你可能会先去目录找到 h 的对应页数,在进行查找,但当你熟练运用字典之后,你可能直接翻到 h 所在的那一部分进行查找了,因为你知道 h 是在中间部分,根本不需要去看前一部分或者后一部分。
我们以前也玩过一种猜数字游戏,一个人说出一个数字,知道答案的人会告诉你,这个数是大了还是小了,然后你不断的调整自己猜的数字,直到猜中正确答案。如果给定的区间是 0 - 100,正确数字是99,而你从1开始往上猜,那么你最多要猜99次;然而使用了二分查找之后你只需要猜测中间数进行比较,不断缩小剩余区间,在经过极少的步骤之后,你就会得到正确的答案。利用二分法查找最多需要步。这会极大地缩减时间
这都是二分法在现实生活中的例子,二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x.。那么接下来,我们就用Python代码来实现二分查找。话不多说,上代码:
def Solution(list,item):
'''
二分法,用来在有序列表里面查找索引
:param list:输入的有序列表
:param item:你需要查找的元素
:return:返回的是查找元素在列表里面的下标
'''
#用来记录尾部数据的位置坐标
high = len(list) - 1
#用来记录头部数据的位置坐标
low = 0
#当中间数值的个数不为1时,循环缩小判断区间
while low <= high:
#mid为中间数值的下标
mid = int((low + high)/2)
#guess为中间数值
guess = list[mid]
#如果中间数值正好为我们要查找的数值,直接返回
if guess == item:
return mid
#如果我们要查找的数值小于中间数值
elif guess > item:
#那么就把high置位
high = mid - 1
#如果我们要查找的数值大于中间数值
else:
#那么就把low置位
low = mid + 1
#主程序
if __name__ == '__main__':
a = [1,2,3,4,5,6,7,8,9]
b = 3
print(Solution(a,b))
注意:我们给定的list列表必须是有序的,否则我们就不可能在有限的步骤之内查找到我们需要的内容
代码分析:
1.首先我们利用哨兵 high 来记录数据尾部的数据位置,利用哨兵 low 记录数据头部分的数据位置,区间 [low, high] 就是存在正确答案的区间。
2.写入一个 while 循环,只要我们的区间 [low , high ] 的数据个数大于1 就继续循环主体程序来缩小区间的大小,直到剩下一个数字,这个数字就是正确答案。这有点类似于高等数学里面的 “夹逼定理” 不断缩小正确答案的空间,直到找到正确答案
2.1计算中间数值 mid的大小(要转换为 int 变量)利用中间值将区间分为大于中间值的一部分跟小于中间值的一部分,通过判断中间值跟正确答案的大小关系来不断缩小猜测区间。
2.2如果猜测的数值等于正确答案,那么直接返回正确答案的下标值
2.3如果猜测的数值大于正确答案,那么说明正确答案存在于两个区间中较小的那个区间,这样就保持 哨兵low不动,哨兵high 变为 mid - 1。
2.4如果猜测的数值小于正确答案,那么说明正确答案存在于两个区间中较大的那个区间,这样就保持 哨兵high不动,哨兵low变为 mid + 1。
2.5 就通过这样不断循环,直至逼近正确答案。