python 二分查找

二分查找

百科

首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

具体实现

import random

# nums_test = sorted(random.randint(0, 100) for _ in range(random.randint(0,100)))
nums_test = [6, 6, 7, 7, 8, 11, 13, 13, 13, 14, 14, 15, 15, 18, 19, 21, 25, 25, 25, 25, 25, 26, 28, 29, 29, 30, 31, 33,
             36, 37, 39, 40, 42, 43, 44, 45, 48, 48, 49, 50, 53, 53, 54, 54, 55, 56, 57, 58, 58, 59, 60, 60, 62, 62, 64,
             69, 69, 70, 70, 71, 72, 74, 77, 78, 79, 79, 80, 81, 83, 85, 88, 91, 92, 93, 94, 95, 95, 98]

print(nums_test)


# 精确匹配
def search_exact(target: int, nums: list = nums_test) -> int:
    l, r = 0, len(nums_test)
    while l < r:
        i = (l + r) // 2
        if nums[i] < target:
            l = i + 1
        else:
            r = i
    return l if nums[l] == target else -1


# 大于等于目标值的第一个
def search_left(target: int, nums: list = nums_test) -> int:
    l, r = 0, len(nums_test) - 1
    while l < r:
        i = (l + r) // 2
        if nums[i] < target:
            l = i + 1
        else:
            r = i
    return l if nums[l] >= target else -1


# 小于等于目标值的最后一个
def search_right(target: int, nums: list = nums_test) -> int:
    l, r = 0, len(nums) - 1
    while l < r:
        i = (l + r + 1) // 2
        if nums[i] <= target:
            l = i
        else:
            r = i - 1
    return l if nums[l] <= target else -1


rp = random.randint(0, len(nums_test))
nums_rotate = nums_test[rp:] + nums_test[:rp]


# 旋转数组中查找最小值
def findMin(nums: list = nums_rotate) -> int:
    l, r = 0, len(nums) - 1
    while l < r:
        i = (l + r) // 2
        if nums[i] > nums[-1]:
            l = i + 1
        else:
            r = i
    return l


# 旋转数组中搜索
# 升序数组nums被分成了俩个互斥的子串,左右颠倒
# 如果t=target在数组中,它要么在左边的升序数组中,要么在右边的升序数组中
# 1. t在左边,则t>right_max, left_min <= t <= left_max
# 2. t在右边,则t<left_min, right_min <= t <= right_max
# 而 right_min <= right_max <= left_min <= left_max (取等号时只有一个元素)
# 由于nums的左右子串互斥,条件1和条件2不可能同时成立
def search_rotate(target: int, nums: list = nums_rotate) -> int:
    l, r = 0, len(nums) - 1
    while l < r:
        i = (l + r) // 2
        print(l, i, r)
        if nums[i] == target:
            return i
        if nums[l] < nums[i]:
            if nums[l] <= target <= nums[i]:
                r = i
            else:
                l = i + 1
        else:
            if nums[i] <= target <= nums[r]:
                l = i
            else:
                r = i - 1
    return -1


t = 25
res_search_l = search_left(t)
print(res_search_l, nums_test[res_search_l - 1:res_search_l + 2])
res_search_r = search_right(t)
print(res_search_r, nums_test[res_search_r - 1:res_search_r + 2])
res_findMin = findMin()
print(nums_rotate)
print(res_findMin, nums_rotate[res_findMin - 1:res_findMin + 2])
res_search_ro = search_rotate(t)
print(res_search_ro, nums_rotate[res_search_ro - 1:res_search_ro + 2])
运行结果
[6, 6, 7, 7, 8, 11, 13, 13, 13, 14, 14, 15, 15, 18, 19, 21, 25, 25, 25, 25, 25, 26, 28, 29, 29, 30, 31, 33, 36, 37, 39, 40, 42, 43, 44, 45, 48, 48, 49, 50, 53, 53, 54, 54, 55, 56, 57, 58, 58, 59, 60, 60, 62, 62, 64, 69, 69, 70, 70, 71, 72, 74, 77, 78, 79, 79, 80, 81, 83, 85, 88, 91, 92, 93, 94, 95, 95, 98]
16 [21, 25, 25]
20 [25, 25, 26]
[62, 64, 69, 69, 70, 70, 71, 72, 74, 77, 78, 79, 79, 80, 81, 83, 85, 88, 91, 92, 93, 94, 95, 95, 98, 6, 6, 7, 7, 8, 11, 13, 13, 13, 14, 14, 15, 15, 18, 19, 21, 25, 25, 25, 25, 25, 26, 28, 29, 29, 30, 31, 33, 36, 37, 39, 40, 42, 43, 44, 45, 48, 48, 49, 50, 53, 53, 54, 54, 55, 56, 57, 58, 58, 59, 60, 60, 62]
25 [98, 6, 6]
0 38 77
38 57 77
38 47 57
38 42 47
42 [25, 25, 25]

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值