• 二分查找及应用


    二分查找针对有序集合,每次查找通过跟中间元素对比大小,将待查找的区间缩小为原来的一半,直到找到要查找的元素或者区间缩小为0.

    二分查找是一种时间复杂度为O(logN)的查找算法,有时甚至比 hash 表中的 O(1)算法效率还要高,因为 hash 表计算 hash 值、解决冲突所花的时间不一定比 O(logN)短。

    二分查找依赖的是顺序表结构,简单的说就是数组,利用数组支持按下标访问的特性实现高速查找。

    二分查找使用场景:

    • 有序数组,且插入、删除不频繁,一次排序多次查找
    • 数据量太小不易使用,顺序遍历即可
    • 数据量太大也不易使用,因为存储这部分数据要耗费大量内存

    快速排序

    既然二分查找依赖的是有序数组,所以先将数据排序,常见的快速排序如下:

    def qsort(arr):
        qsort_p(arr, 0, len(arr)-1)
    
    def qsort_p(arr, p, q):
        if p < q:
            pivot = arr[q]
            i = p
            for j in range(p, q):
                if arr[j] < pivot:
                    arr[i], arr[j] = arr[j], arr[i]
                    i += 1
            arr[i], arr[q] = arr[q], arr[i]
            qsort(arr, p, i-1)
            qsort(arr, i+1, q)
    
    

    for 循环借助插入排序的思想,变量 i 将数据一分为二:已处理区间和未处理区间,每次从 i..q-1 中取出一个元素arr[j]与 pivot 对比,如果小于 pivot 则将此数据放到已处理区间的末尾也就是 arr[i] 的位置。循环完成将 arr[i] 与 pivot 值互换,arr[i] 左边就是小于 pivot 的,右边是大于 pivot 的数据。

    二分查找的应用

    查找值等于给定值的元素

    代码实现:

    def bsearch(arr, val):
        low, high = 0, len(arr) - 1
        while low <= high:
            mid = low + (high - low) // 2
            if arr[mid] > val:
                high = mid - 1
            elif arr[mid] < val:
                low = mid + 1
            else:
                return mid
        return -1
    

    每次都与区间中间值 arr[mid] 比较,缩小比较范围。若大于 arr[mid] 则更新 low = mid + 1;若小于 arr[mid] 则更新 high = mid - 1

    计算平方根

    精确到小数点后6位

    def bsqrt(n):
        low, high = 0, n
        while high - low > 0.000001:
            mid = low + (high - low) / 2
            if mid * mid > n:
                high = mid
            elif mid * mid < n:
                low = mid
            else:
                return mid
        return mid
    

    在数组中下标是整数,所以用了 (high - low) // 2,而这里直接使用的小数乘法,所以是正常的除法

    二分查找变形问题

    查找第一个值等于给定值的元素

    在找到给定值后不停下,而是继续往 查找,直到 mid 为 0 或者 mid 的前一个值不等于 val

    def first_equal(arr, val):
        low, high = 0, len(arr) - 1
        while low <= high:
            mid = low + (high - low) // 2
            if arr[mid] < val:
                low = mid + 1
            elif arr[mid] > val:
                high = mid - 1
            else:
                if mid == 0 or arr[mid-1] != val:
                    return mid
                else:
                    high = mid - 1
        return -1
    

    查找最后一个值等于给定值的元素

    在找到给定值后不停下,而是继续往 查找,直到 mid 为 len(arr) - 1 或者 mid 的后一个值不等于 val

    def last_equal(arr, val):
        length = len(arr)
        low, high = 0, length - 1
        while low <= high:
            mid = low + (high - low) // 2
            if arr[mid] > val:
                high = mid - 1
            elif arr[mid] < val:
                low = mid + 1
            else:
                if mid == length - 1 or arr[mid+1] != val:
                    return mid
                else:
                    low = mid + 1
        return -1
    

    查找第一个值大于等于给定值的元素

    一直往 查找,直到 mid 为 0 或者 mid 的前一个值小于 val

    def first_great(arr, val):
        length = len(arr)
        low, high = 0, length - 1
        while low <= high:
            mid = low + (high - low) // 2
            if arr[mid] < val:
                low = mid + 1
            else:
                if mid == 0 or arr[mid-1] < val:
                    return mid
                high = mid - 1
        return -1
    

    查找最后一个值小于等于给定值的元素

    一直往 查找,直到 mid 为 len(arr)-1 或者 mid 的后一个值大于 val

    def last_less(arr, val):
        length = len(arr)
        low, high = 0, length - 1
        while low <= high:
            mid = low + (high - low) // 2
            if arr[mid] <= val:
                if mid == length - 1 or arr[mid+1] > val:
                    return mid
                else:
                    low = mid + 1
            else:
                high = mid - 1
        return -1
    

    容易出错的地方

    1. 循环退出条件是 low <= high
    2. mid 的取值,如果写成 (low+high) // 2 可能会溢出
    3. low 和 high 的更新,一定是 low = mid + 1 和 high = mid - 1 ,如果写成 low = mid 或 high = mid,当 mid = 3 时,如果 arr[3] 不等于 val 就会发生死循环
  • 相关阅读:
    过完年又是跳槽涨工资的好机会了,许多毕业生也正打算参与社会,希望我的经历能给你们带来点什么
    临时表dataTable 求助,
    C#代码与javaScript函数的相互调用(转)
    一些基本的GIS 和国土方面知识(来自网上,序号都没改)
    VS 2008 安装求助 麻烦看下 下班就取下来,感觉不适合放这
    有关环境 错误 的记录
    我公司在招人 AE的
    ARCgis server 安装与起步(转自冬儿的BLOG )
    pytorch入门之安装和配置
    python出现编码问题的原因及编码问题的解决
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/12243150.html
Copyright © 2020-2023  润新知