1 前言
关于二分查找,首先来看一个段子,见下图:
有点意思,虽然是个段子,但是大妈查找有问题书的方式其实就是今天我们要说的二分查找!也叫折半查找!下面就跟随小编的角度来具体看看什么叫二分查找吧!
2 什么叫二分查找?
- 搜索是在一个项目集合中找到一个特定项目的算法过程。
- 搜索通常的答案是真的或假的,因为该项目是否存在。 搜索的几种常见方法:
- 顺序查找
- 二分法查找
- 二叉树查找
- 哈希查找
关于顺序查找就比较简单了,就是从头开始,一个元素一个元素的遍历!效率比较低!
下面主要讲述二分查找!
-
二分查找又称折半查找。优缺点见下:
- 优点:比较次数少,查找速度快,平均性能好;
- 缺点:要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。
-
二分查找的实现过程如下:
- 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较
- 如果两者相等,则查找成功;
- 否则利用中间位置记录将表分成前、后两个子表
- 如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。
- 重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
-
图解:要查找的元素为4
3 代码实现
3.1 递归版本
递归思路:
- 首先要对序列进行排序吗?不需要,必须是有序的!
- 排序ok之后 开始考虑二分查找 所以是不是还需要再传入一个参数 就是一个具体的数值?判断这个值在不在list当中?yes!
- 首先对序列进行对半砍,然后判断中值和传入的value进行比较!大于则在右边查找 小于在左边查找!递归调用函数,参数变为新的list!
- 上述循环加一个终止条件 也就是当list元素只有一个的时候!
递归版本:
def binary_search(alist, value):
'''二分查找'''
n = len(alist)
mid = (0+n) // 2
while n > 0: # 递归的终止条件 即大于等于一个元素的时候
if alist[mid] == value:
return True
elif value < alist[mid]:
# 左半部分查找
return binary_search(alist[:mid],value)
else:
# 右半部分查找
return binary_search(alist[mid+1:], value)
return False
testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
print(binary_search(testlist, 3))
print(binary_search(testlist, 13))
False
True
li = [17, 20, 26, 31, 44, 54, 55, 77, 93]
print(binary_search(li, 55))
print(binary_search(li, 100))
True
False
3.2 非递归版本
非递归思路:
- 不是将切片后的list传入,而是每次改变位置即可!
- 原理和上面递归的类似,就是二分查找,小于中间值则在左边查,大于右边查,只是每次修改起始和终止的位置!
def binary_search(alist, value):
'''二分查找 非递归版本'''
n = len(alist)
first = 0
last = n-1
while first <= last:
# 必须在循环体内部计算 因为每次查找要么first要么last会发生变化
mid = (first + last) // 2
if alist[mid] == value:
return True
elif value < alist[mid]:
# 修改查找范围
last = mid - 1
else:
first = mid + 1
return False
testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
print(binary_search(testlist, 3))
print(binary_search(testlist, 13))
False
True
li = [17, 20, 26, 31, 44, 54, 55, 77, 93]
print(binary_search(li, 55))
print(binary_search(li, 100))
True
False
4 时间复杂度
二分查找(折半查找)时间复杂度:
- 最优就是常数 O ( 1 ) O(1) O(1),因为一查就查到了
- 最差是对数复杂度 O ( l o g n ) O(logn) O(logn)
普通查找时间复杂度:
- 最优就是常数 O ( 1 ) O(1) O(1),因为一查就查到了
- 最差是线性复杂度 O ( n ) O(n) O(n)
5 知识点补充
- " / " 表示浮点数除法,返回浮点结果;
- " // " 表示整数除法,返回不大于结果的一个最大的整数
6 / 4
1.5
6 // 4
1