3、二分查找算法的3种写法(算法基础—查找算法)

二分查找:

又叫折半查找,从有序列表的初始候选区li[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半。

第一种简单写法:

逻辑:通过取中间位置的值来对比,不断调整候选区的范围,匹配到则范围该直到如果最后匹配成功。
由于left和right的值一直跟随mid一同变化,所以最后得到的mid值,是真正的位置

def binary_search2(li, val):
    '''假设输入的是个升序的列表,获取中间位置的值跟要查找的值val作对比,
    如果比val大,则取中间位置左边部分继续二分查找'''
    left = 0
    right = len(li) - 1
    while left <= right:       # 使用left和right变量控制候选区的范围,并没有改变传进来的列表
        mid = (left + right) // 2
        if li[mid] == val:
            return mid
        elif li[mid] > val:   # 待查找的值在mid左侧
            right = mid - 1
        else:   # 待查找的值在mid右侧
            left = mid + 1
    return None

li = [i for i in range(0, 10000000, 2)]

print(binary_search2(li, 39898))

第二种:递归写法1

这种写法的逻辑同样是选取中间位置的值出来做对比,不同的是这种会不断裁剪列表,确认不在匹配范围内的数据则会被舍弃,只保留可能存在该值的区域。

缺点:此种写法只能确认待查找的值是否在列表中,无法返回该值处在列表的位置。

def binary_search(li, val):
    '''假设输入的是个升序的列表,获取中间位置的值跟要查找的值val作对比,
    如果比val大,则取中间位置左边部分继续二分查找'''
    '''递归会由于过程中会修改列表,所以如果直接返回mid的值,
    并不是我们想要的索引值'''
    if len(li) == 0:
        return False
    mid = len(li)//2
    if li[mid] == val:
        return True
    if li[mid] > val:
        li = li[:mid]
        return binary_search(li, val)
    else:
        li = li[mid+1:]
        return binary_search(li, val)

li = [i for i in range(10)]
print(li)
print(binary_search(li, 7))

第三种:递归写法2

上一个写法无法返回待查找值在列表中的位置,但可以稍微改进一下的,让它能准确返回待查找值的位置

修改逻辑:
上一个写法无法返回待查找值的位置主要是因为列表在查找的过程中被我们不断修剪,最后一次即使找到了,该位置也不是最初的位置。

所以如果我们能在修剪列表的过程中,把裁剪的长度记录下来,一直传递下去,最后一次查到时把它加上去,就是它最初在列表中的位置了。

需要注意的是,并不是每一次裁剪都需要把裁剪长度记录下来。只有当你取列表的右半部分时,才需要加上,当你取列表的左半部分时,不需要加上。

下图圈出部分为新增代码:
在这里插入图片描述

完整代码:

def binary_search(li, val, idx=0):
    '''假设输入的是个升序的列表,获取中间位置的值跟要查找的值val作对比,
    如果比val大,则取中间位置左边部分继续二分查找'''
    if len(li) == 0:
        return False
    mid = len(li)//2
    if li[mid] == val:
        return idx + mid
    if li[mid] > val:
        li = li[:mid]
        return binary_search(li, val, idx)
    else:
        idx += len(li[:mid+1])
        li = li[mid+1:]
        return binary_search(li, val, idx)

li = [i for i in range(60)]
print(li)
print(binary_search(li, 57))
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值