假设你在家里柜子中找到一本破旧的英汉大词典(七八百页的那种,也有可能是武功秘籍),你想找到以L开头的单词,你可以从头开始,一页一页的翻,直到天荒地老,但聪明的你不那么做,你从中间开始翻,因为以L开头的单词在词典中间,你看,你无意间就使出了二分查找!
二分查找是一种算法,它的输入是个有序的元素列表,记住,这个列表一定是有序的!!!你要找的元素包含在其中,二分查找要做的就是返回它的位置,如果没有包含,就返回NULL。每次都要找到中间位置的值来与你要查找的值比较。
1.二分法查找的思路
(1)从有序数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行(2)。
(2)如果目标元素大于中间元素,则在数组大于中间元素的那一半区域查找;如果目标元素小于中间元素,则在数组小于中间元素的那一半区域查找,然后重复步骤(1)的操作。
(3)如果某一步数组为空,则表示找不到目标元素,结束查找。
2.图解二分查找
下面给个例子说明这个过程的实现
给定一个有序数组Arr, 里面有10个元素,我们查找的目标数字是key = 56,由于这个数组很短,我们能看出查找值的位置是8
下面定义两个边界下标low和high,定义中间下标mid;
low = 0; high = len(Arr) - 1 ; Python中的位置是从零开始的。
mid = (low+high) // 2; “//”在Python中是向下取整。
在进行每一步的比较时,low<=high;
二分查找第一次找到中间下标mid = (0+9) // 2 = 4;
此时Arr[4] = 11,比当前key = 56值小,所以我们在右半边查找,令low = mid + 1 = 5;high不变;
我们找到中间下标mid = (5+9) // 2 =7;
Arr[7] = 33,比当前key = 56值小,所以我们仍在右半边查找,令low = mid + 1 = 8;high不变;
我们找到中间下标 mid = (8+9) // 2 =8;
做完最后一次比较后,此时key == Arr[mid] == Arr[8];停止查找,返回位置值mid。
一般而言,对于包含n个元素的列表,用二分法查找,最多需要log2(n)步
3.python算法实现
我们自定义一个函数binary_search来实现二分查找
def binary_search(my_list,item):
first_loc = 0 #第一个位置
last_loc = len(my_list)-1 #最后一个位置
while first_loc <= last_loc: #只要list没有缩减到只包含一个元素,即只要它是非空的,就一直查找。
mid = (first_loc + last_loc)//2 #检查中间元素 自动向下取整 相当于 int((first_loc + last_loc)/2)
guess = my_list[mid]
if guess ==item:
return mid
if guess < item:
first_loc = mid + 1
else:
last_loc = mid - 1
return None
接下来我们调用定义的binary_search函数,用二分法查找出上面列表的key = 56的位置索引。
返回的位置索引是8,和我们图解法做出的结果一样,大功告成!!!
这就是二分查找,你get到了吗?