【Algorithm】二分查找法以及其变种

前言

二分查找法用了这么久,总结一下常见的变种,这里看了很多别人的文章,在这里把它们说的总结一下(其实维基百科里面写的就非常全面了,不仅提出了问题,还有关于二叉查找的一些变种,链接可以在下面的介绍里面点击英文)


什么是二分查找

二分查找Binary search)也称折半查找,它是一种效率较高的查找方法

算法前提

  • 线性表必须采用顺序存储结构
  • 表中元素按关键字有序排列

算法复杂度

采用分治策略,可在最坏的情况下用 O(log n) 完成搜索任务

经典的二分查找法

伪代码

function binary_search(A, n, T):
    L := 0
    R := n − 1
    while L <= R:
        m := floor((L + R) / 2)
        if A[m] < T:
            L := m + 1
        else if A[m] > T:
            R := m - 1
        else:
            return m
    return unsuccessful

溢出问题

在你的写法里面, mid 可能是是这样算出来的:

int mid = (l + r) / 2;

这一个操作很可能会造成溢出,有一个很简单的改进方法:

int mid = l + (r - l) / 2;

这样就能保证不会出现溢出的问题

C / C++

int binary_search(int *array, int size, int key){
    int l = 0;
    int r = size - 1;
    while(l <= r){
        int mid = l + (r - l) / 2;
        if(array[mid] < key) l = mid + 1;
        else if(array[mid] > key) r = mid - 1;
        else return mid;
    }
    return -1;
}

二分查找的变种

第一类:查找和目标值相等的数

这个就是最经典的二分查找的目的,没什么好说的

int binary_search(int *array, int size, int key){
    int l = 0;
    int r = size - 1;
    while(l <= r){
        int mid = l + (r - l) / 2;
        if(array[mid] < key) l = mid + 1;
        else if(array[mid] > key) r = mid - 1;
        else return mid;
    }
    return -1;
}

第二类:查找第一个不小于目标值的数/查找最后一个小于目标值的数

查找第一个不小于目标值的数(第一个 >= 目标值) 对应C++的STL的函数 lower_bound

注意可能会存在下面的情况

  • 目标值不一定会在数组中出现
  • 与目标值相等的数在数组中并不唯一,即有多个的情况
int binary_search_lower_bound(int *array, int size, int key){
    int l = 0;
    int r = size - 1;
    while(l <= r){
        int mid = l + (r - l) / 2;
        if(array[mid] < key) l = mid + 1;
        else r = mid - 1;
    }
    return r + 1;
}

它可以变形为查找最后一个小于目标值的数(最后一个 < 目标值),其实就是上面的往左移一位

{
    ...
    return r;
}

第三类:查找第一个大于目标值的数/查找最后一个不大于目标值的数

查找第一个大于目标值的数(第一个 > 目标值) 这类变种对应C++的STL的函数 upper_bound

与第二类相似,同时也可能出现下面的情况

  • 目标值不一定会在数组中出现
  • 与目标值相等的数在数组中并不唯一,即有多个的情况
int binary_search_upper_bound(int *array, int size, int key){
    int l = 0;
    int r = size - 1;
    while(l <= r){
        int mid = l + (r - l) / 2;
        if(array[mid] <= key) l = mid + 1;
        else r = mid - 1;
    }
    return r + 1;
}

它可以变形为查找最后一个不大于目标值的数(最后一个 <= 目标值),其实就是上面的往左移一位

{
    ...
    return r;
}

其他

待补充

参考文章

[1] 二分搜索法小结: http://www.cnblogs.com/grandyang/p/6854825.html

[2] 你真的会写二分查找吗:https://www.cnblogs.com/luoxn28/p/5767571.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值