二分查找

二分查找使用前提:

1.有序数组(单调递增或递减)

2.无重复元素

 而使用方法:

二分查找一般可以定义两种区间

1.全闭--[l, r] 相当于while l <= r

2.左闭--[l, r) 相当于while l < r

选择一种区间后就要时刻牢记区间的定义,在每次处理边界时会用到,否则写出来得代码就是靠蒙的

例如:

给一个有序数组A和一个目标值S,求目标值在数组中的下标,如果没找到返回-1

A = [-2,0,2,4,9,11]    S = 9

第一种定义:全闭

分析:

一、目标值在全闭区间中

1.首先要使用while l <= r

2.处理边间

(1)首先找到数组的中间长度mid

(2)其次,根据A[mid] 与s对比,判断我们应该在哪个区间去搜索 --二分

  <1> 当A[mid] > s,我们就应该在mid的左边去搜索(记住,数组是有序的递增的;如果数组有序递减搜索区间就要变成去mid右边搜索),即搜索区域变为[l, mid - 1],也就是把 r = mid - 1

    为什么搜索区域不能是[l, mid]?--因为A[mid] > S 所以A[mid] 不会等于S,mid就不是我们要找到的值

    为什么判断条件不能是A[mid] >= S?--我们要找的就是数组中等于S的值,如果判断条件是大于等于,那么当前的值到底是大于S(应该继续搜索),还是等于S呢(停止搜索)

  <2> 当A[mid] < s,我们应该在mid右边搜索

  <3> 当A[mid] == s,停止搜索

def search(A,s):
    l = 0
    r = len(A) - 1
    while l <= r:
        mid = (l + r) // 2 #找到中间位置
        if A[mid] > s: #如果大于s,则搜索区间变为[l, mid - 1]即r = mid - 1
            r = mid - 1 
        elif A[mid] < s: #如果小于s,则搜索区间变为[mid + 1, r]即l = mid + 1
            l = mid + 1
        else: #等于s则停止搜索
            return mid
    return -1
A = [-2,0,2,4,9,11] 
S = 9
print(search(A,S))

结果为4

二、目标值在左闭区间

1.首先要使用while l < r

2.处理边间

(1)首先找到数组的中间长度mid

(2)其次,根据A[mid] 与s对比,判断我们应该在哪个区间去搜索 --二分

  <1> 当A[mid] > s,我们就应该在mid的左边去搜索(记住,数组是有序的递增的;如果数组有序递减搜索区间就要变成去mid右边搜索),即搜索区域变为[l, mid),也就是把 r = mid

    为什么搜索区域不是[l, mid - 1)?--记住我们的搜索区间是左闭,且A[mid]不等于s,所以mid肯定不是我们要找的值,对于开区间,数组的下标是到不了端点的。

    例如:当mid = 9 ,l = 0时,我们如果用[l, mid - 1)搜索即[0, 8)搜索那么我们的搜索区间就相当于[0, 7](对于开区间,数组的下标是到不了端点的),这时是不是就漏掉了下标为8的值;而用[l , mid)搜索,则搜索区间为[0, 9)

    这就相当于搜索区间[0, 8],这才是我们一个完整的搜索区间

    为什么判断条件不能是A[mid] >= S?--我们要找的就是数组中等于S的值,如果判断条件是大于等于,那么当前的值到底是大于S(应该继续搜索),还是等于S呢(停止搜索)

  <2> 当A[mid] < s,我们应该在mid右边搜索

  <3> 当A[mid] == s,停止搜索

def search(A,s):
    l = 0
    r = len(A) - 1
    while l < r:
        mid = (l + r) // 2 #找到中间位置
        if A[mid] > s: #如果大于s,则搜索区间变为[l, mid]即r = mid
            r = mid 
        elif A[mid] < s: #如果小于s,则搜索区间变为[mid + 1, r]即l = mid + 1
            l = mid + 1
        else: #等于s则停止搜索
            return mid
    return -1
A = [-2,0,2,4,9,11] 
S = 9
print(search(A,S))

上面两种就是标准的二分查找模板,所以在考虑二分查找时要时时刻刻牢记区间的定义,这样在处理边间时才不会糊涂。

posted @ 2022-12-10 15:03  *小白*  阅读(67)  评论(0)    收藏  举报