二分查找

本文介绍了二分查找的基本概念和Python实现,包括如何使用递归实现二分查找算法。通过一个实例展示了如何在素数列表中使用二分查找检索特定数值的索引,强调了递归函数的终止条件和返回值。同时,也提到了使用循环实现二分查找的逻辑和终止条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二分查找顾名思义,平分成两份查找(以网易云课堂 第六周作业为例,使用Python语言)

两点入门二分查找:

a. 猜测的值 = 中间值 =(low+high)/2 —— 二分的意义

b. 中间值<实际值,low = 中间值位置+1;中间值>实际值,high = 中间值-1

提供一个简易的代码模板(默认能够找到——如果不存在这个值也没必要查找了,提前使用in来判断是否存在):

def search(sequence, number, lower, upper):
    if lower == upper:
        assert number == sequence[upper] # 断言一定能找到,找不到则异常
        return upper
    else:
        middle = (lower + upper)//2
        if number > sequence[middle]:
            return search(sequence, number, middle+1, upper)
        else: # there has 2 situation--middle is not (middle-1)
            return search(sequence,number,lower,middle)



一些实例:

1.定义一个 prime() 函数求整数 n 以内(不包括n)的所有素数(1不是素数),并返回一个按照升序排列的素数列表。使用递归来实现一个二分查找算法函数bi_search(),该函数实现检索任意一个整数在 prime() 函数生成的素数列表中位置(索引)的功能,并返回该位置的索引值,若该数不存在则返回 -1。

思考:

要查找位置并且返回索引值,一般解决方法很简单:使用循环判断 / 列表的index方法,但是要是列表很长东西很多,那么这样的从头开始循环的话则效率会很低,那么使用二分查找。

解:

说到递归函数,不得不再一次强调:一定要有终止条件返回;非终止条件的递归过程,调用自身前面一定要有return,否则返回的是None。

这道题中的终止条件便是:返回该位置的索引值,若该数不存在则返回 -1

def prime(n):
    lst = []
    for i in range(2, n):
        for j in range(2, i):
            if i % j == 0:
                break
        else:
            lst.append(i)
    return lst
n = 10  # assume n = 10
lst = prime(n)


x = raw_input("Enter num: ")
x = int(x) # raw_input() return a string

def bi_search(x, low, high):
    guess = (low + high) / 2
    print lst[guess], x
    if (x == lst[guess]):
        return guess  
    elif low > high:
        return -1
    elif lst[guess] > x:
        print 'lst[guess] > x'
        return bi_search(x, low, guess -1) # !!! take care
    elif lst[guess] < x:
        return bi_search(x, guess + 1, high) # !!! take care

再次通过同学ZHT的启发,简化下程序:首先利用Python 的 “in” 运算符判断数字是否在列表内(先决条件),再进行查找。

既然循环的先决条件是有x 存在于列表当中,所以必然就是能够找到的 x 的位置的,故终止条件只有一个:x 的位置

def bi_serach(lst,n):
    lenth = len(lst)
    while n in lst: 
        if n == lst[lenth / 2]:
            return lenth / 2
        elif n < lst[lenth / 2]:
            lst = lst[:lenth / 2]
            return bi_serach(lst,n)
        else:
            lst = lst[lenth / 2 + 1:]
            return bi_serach(lst,n) + lenth /2 + 1 # after slicing you must do
    return -1 # same indent with "While"
上述程序有一个需要注意的地方:切片操作,往后切片之后一定要注意下标的变化要还原, 之前提到过这样一个问题:“注意细节上的逻辑错误,在swap中,第二个参数不能够直接传mi,因为 mi 是在砍掉了 i 项之后的 nLst 中的位置 ≠ lst中的位置, 所以需要给mi 补上 i 才是 lst 中正确的位置。”

另外,使用循环实现二分查找:

同样需要找准终止条件,依然是:找到了 & 没找到的情况

逻辑是:没有找到就持续循环,找到了就return,故循环结束条件就是没有找到任何匹配position。

def bi_search(x, low, high):
   while high >= low:
       guess = (high + low) / 2
       if x == lst[guess]:
           return guess
       elif lst[guess] > x:
           high = guess - 1
       else:
           low = guess +1
   return -1

当然,可以依照上述递归的方法也进行改装(循环的先决条件是,x 存在于列表当中),只需要将 while 条件(修改 while high >= low: )
while x in lst:
改变即可。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值