作为数据结构接触到的入门第一个算法,很多人对它不以为然,但是作为小白学习还是很有必要的,循序渐进,打开算法的大门
假如你要登录王者荣耀,当你这样做时,QQ或者微信必须核实你是否有其游戏的账户,因此在数据库中查找你的用户名和账号。如果你的用户名为king,腾讯可以从以A开头的部分开始查找,但更合乎逻辑的做法是从中间开始查找。
二分查找是一种算法,要求输入是一个有序的元素列表,我们结合程序的话,如果要查找的元素包含在列表中,则返回它的位置,否则返回NULL。
关于详细的原理,可以引入一个耳熟能详的小游戏——猜数字
将范围设定为1~100,你需要在最短次数内猜到这个数字,你每次猜测,我会说小了或者大了,直到猜中。
假如你从1开始依次往上猜,如果我想的数字是99,你岂不是需要猜99次?显然令人啼笑皆非
你可能会说,我怎么可能这么傻,那么,我们就引申出了一种更佳的猜法:
从50开始,每次都从中间值开始猜,如果我说小了,那么你下一次的猜测就从75开始,反之就从25开始。无论如何,余下的数字都排除了一半,你猜的一直是中间的数字,所以每次都能排除一半。
最终的结果就是,无论我想的是什么数字,你在7次之内都能找到,因为每次都排除掉一半。
而且,元素越多的情况下,二分查找相较于简单查找的优势只会更大
有数学基础的你可能已经发现了,对于包含n个元素的列表,二分查找最多需要log2^n次,简单查找最多需要n次!
如果你不清楚对数的概念,可以先去了解一下,对于后续数据结构的学习大有裨益。
接下来结合python代码对二分查找进行简单实现
这里的示例使用了数组,不熟悉数组的可以先去了解一下相关概念,后续数据结构会经常出现
简单说就是:将一系列元素存储在一系列相邻的盒子中,这些盒子从0开始编号,因此第一个盒子的位置为0,第二个位置为1,第三个就是2……以此类推
# 定义二分查找函数,接收一个有序列表和待查找元素
def binary_search(list, item):
# 初始化查找范围的最低索引
low = 0
# 初始化查找范围的最高索引(列表长度减1)
high = len(list) - 1
# 当查找范围存在时循环(低索引不大于高索引)
while low <= high:
# 计算中间索引:使用整数除法避免浮点数
mid = (low + high) // 2 # 修改1:使用//进行整数除法
# 获取中间索引对应的值
guess = list[mid]
# 如果中间值等于目标值
if guess == item:
# 返回目标值的索引
return mid
# 如果中间值大于目标值
if guess > item:
# 将查找范围上限设为中间索引前一位(排除右半部分)
high = mid - 1
# 如果中间值小于目标值
else:
# 将查找范围下限设为中间索引后一位(排除左半部分)
low = mid + 1
# 未找到目标值,返回None(已移到循环外) # 修改2:将return None移到while循环外
return None
# 创建测试用的有序列表
my_list = [1, 3, 5, 7, 9]
# 查找元素3并打印结果(预期返回索引1) # 修改3:使用print()函数
print(binary_search(my_list, 3))
# 查找不存在的元素-1并打印结果(预期返回None) # 修改4:使用print()函数
print(binary_search(my_list, -1))
以查找数字3为例,查找过程如下:
初始范围:[1,3,5,7,9] (low=0, high=4)
2. 中间索引:2 → 值5 > 3 → 调整high=1
3. 新范围:[1,3] (low=0, high=1)
4. 中间索引:0 → 值1 < 3 → 调整low=1
5. 中间索引:1 → 值3 == 3 → 返回索引1