最全二分查找的各种版本 套路归纳+递归代码 大于、大于等于、小于、小于等于,最左边,最右边 Python实现 折半查找

二分查找(折半查找)的各种版本

网上各类零零散散的二分查找,很多都没遵循前闭后开,还有很多代码运行到最后要额外判断left和right,运行是没问题,但是并不优雅,有强迫症的我看着很不舒服。
以下我自己总结一下二分查找的各种版本,递归实现。(水平有限,如有错误敬请指正)

注:以下代码及总结遵循前闭后开原则:begin为起始下标,end为末尾下标的后一个,与STL等库统一。

先上总结:

套路十分简单!只要改改下次递归区间和mid的取整方式,一切迎刃而解!

以下归纳不包括查找恰好等于target的算法,恰好等于的单独讨论。
另外,以下算法不考虑结果不在数组内的情况,这个在外层特殊判断即可。(比如数组[1,2]要查找第一个大于2的,这个结果不在数组内)

什么时候结束:

begin + 1 == end时,说明区间里只有唯一一个数。
很多地方都用大于等于、小于等于之类的实现。这里精确到等于号,不稀里糊涂。(有些版本用≥、≤当然没错,但有时到最后要判断左右两值,虽然也具有很好的通用性,但是没那么紧凑。)

下一次递归的区间:

下一次递归往左还往右:target小于nums[mid]往左,大于nums[mid]往右。然后再判断等于的情况往哪。
具体的区间是什么:重点就在于,nums[mid]应该包含在左边的区间还是右边的区间,根据情况决定

mid到底是向上还是向下取整:

如果下一次递归,nums[mid]放在左区间就向下取整,放在右区间就向上取整。
原因:若nums[mid]放在左区间,那么num[mid]就会成为下一次递归中最右边的一个,如果这时候是向上取整,那么mid值可能依然是最右边的一个元素(比如两个元素的数组[0,1]如果用向上取整求mid,结果是1),导致死循环。

遵循前闭后开原则中,begin + (end - begin - 1) // 2是向下取整,不减1是向上取整
("//"在Python里是整除的意思,其他语言自行修改)

 

查找恰好等于target的(如果要查找第一个恰好等于的或者最后一个恰好等于的,根据后面的>=和<=修改即可)

# 二分查找,返回下标,不存在返回-1
# 如果要查找第一个恰好等于的或者最后一个恰好等于的,根据后面的>=和<=修改下即可
def binary_search_1(nums, target, begin, end):
    if begin == end:
        return -1
    mid = begin + (end - begin - 1) // 2
    if target < nums[mid]:
        return binary_search_1(nums, target, begin, mid)
    elif target > nums[mid]:
        return binary_search_1(nums, target, mid + 1, end)
    else:
        return mid

查找第一个>=target的(若相等则返回最左边的)

def binary_search_2(nums, target, begin, end):
    if begin + 1 == end:
        return begin
    mid = begin + (end - begin - 1) // 2
    if target <= nums[mid]:
        return binary_search_2(nums, target, begin, mid + 1)
    else:
        return binary_search_2(nums, target, mid + 1, end)

查找最后一个<=target的(若相等则返回最右边的)

def binary_search_3(nums, target, begin, end):
    if begin + 1 == end:
        return begin
    mid = begin + (end - begin) // 2
    if target < nums[mid]:
        return binary_search_3(nums, target, begin, mid)
    else:
        return binary_search_3(nums, target, mid, end)

查找第一个>target的

def binary_search_4(nums, target, begin, end):
    if begin + 1 == end:
        return begin
    mid = begin + (end - begin - 1) // 2
    if target < nums[mid]:
        return binary_search_4(nums, target, begin, mid + 1)
    else:
        return binary_search_4(nums, target, mid + 1, end)

查找最后一个<target的

def binary_search_5(nums, target, begin, end):
    if begin + 1 == end:
        return begin
    mid = begin + (end - begin) // 2
    if target <= nums[mid]:
        return binary_search_5(nums, target, begin, mid)
    else:
        return binary_search_5(nums, target, mid, end)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值