【算法专题】秒懂如何运用二分查找算法

简介: 【算法专题】秒懂如何运用二分查找算法

正文


一、二分查找的实现


对于给定的已经有序的数列,我们需要在该数列中查找是否存在某个元素。


每次都与数列最中间的元素进行比较,可以缩小一半的查找区间,直至找到目标元素或者区间被缩小为0,元素不存在。比如下面的数列中,我们想要查找元素19,那么大致的过程就是这样的:


7.png


二分查找过程示意图


使用代码实现如下:

    public static void main(String[] args) {
        int[] data = {8, 11, 19, 23, 27, 33, 45, 55, 67, 98};
        int result = binarySearch(data, data.length, 19);
        log.info("查找元素19的位置是:{}", result);
    }
    public static int binarySearch(int[] data, int size, int target) {
        int low = 0;
        int high = size - 1;
        while (low <= high) {
            int middle = (low + high) / 2;
            if (data[middle] == target) {
                return middle;
            } else if (data[middle] < target) {
                low = middle + 1;
            } else {
                high = middle - 1;
            }
        }
        log.info("元素{}查找不存在!", target);
        return -1;
    }

二分查找的时间复杂度是O(logn),对数阶时间复杂度的算法效率非常高。


二、二分查找的特点及使用场景


二分查找必须依赖以下条件才能发挥作用:

  • 数据结构一定要是顺序表,比如数组。如果是不支持随机访问的数据结构,那么二分查找就无法使用;
  • 待查找的数列一定要是有序的。如果给定的数列是无序的,那么我们就必须先使用排序算法将数列进行排序,否则也无法使用二分查找;
  • 不适合频繁插入和删除的数列;因为数列需要保持有序,要么在插入和删除的时候保证有序,要么在插入数列后使用排序算法进行排序,这些都是时间开销;
  • 不适合数据量太小的数列;数列太小,直接顺序遍历说不定更快,也更简单;但是有一种场景除外,就是每次元素与元素的比较是比较耗时的,这个比较操作耗时占整个遍历算法时间的大部分,那么使用二分查找就能有效减少元素比较的次数,从而节约时间;
  • 不适合数据量太大的数列;二分查找作用的数据结构是顺序表,也就是数组,数组是需要连续的内存空间的,系统并不一定有这么大的连续内存空间可以使用;


三、二分查找相关的变体


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

    public static void main(String[] args) {
        int[] data = {8, 11, 19, 19, 19, 33, 45, 55, 67, 98};
        int result = binarySearch1(data, data.length, 19);
        log.info("查找元素19的位置是:{}", result);
    }
    public static int binarySearch1(int[] data, int size, int target) {
        int low = 0;
        int high = size - 1;
        while(low <= high){
            int middle = (low + high) / 2;
            if(data[middle] > target){
                high = middle - 1;
            } else if(data[middle] < target){
                low = middle + 1;
            } else {
                // 当前元素等于目标元素,但是不一定是第一个等于目标元素的
                if((middle == 0) || (data[middle-1] != target)){
                    // 说明当前middle是第一个等于目标元素的
                    return middle;
                } else {
                    // 继续在middle的前半区间进行查找
                    high = middle - 1;
                }
            }
        }
        return -1;
    }


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

else {
                // 当前元素等于目标元素,但是不一定是最后一个等于目标元素的
                if((middle == size-1) || (data[middle+1] != target)){
                    // 说明当前middle是最后一个等于目标元素的
                    return middle;
                } else {
                    // 继续在middle的后半区间进行查找
                    low = middle + 1;
                }
}


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

public static int binarySearch3(int[] data, int size, int target) {
        int low = 0;
        int high = size - 1;
        while(low <= high){
            int middle = (low + high) / 2;
            if(data[middle] >= target){
                if(middle == 0 || data[middle-1] < target){
                    // 是第一个大于等于target的位置
                    return middle;
                } else {
                    // 继续往middle的前半部分去找
                    high = middle - 1;
                }
            } else {
                // 继续往middle的后半部分去找
                low = middle + 1;
            }
        }
        return -1;
    }


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

public static int binarySearch4(int[] data, int size, int target) {
        int low = 0;
        int high = size - 1;
        while(low <= high){
            int middle = (low + high) / 2;
            if(data[middle] <= target){
                if(middle == (size-1) || data[middle+1] > target){
                    return middle;
                } else {
                    low = middle + 1;
                }
            } else {
                high = middle - 1;
            }
        }
        return -1;
    }


四、总结


在实际的查找业务场景中,凡是可以使用二分查找的问题都可以使用散列表和二叉查找树来完成,而且后面两者的使用频率要更高。


什么情况下才使用二分查找呢?用于求解近似查找的问题上,比如上面描述的四种二分查找变体问题,而这类问题使用散列表、二叉查找树或者别的数据结构和算法就不太好实现。

相关文章
|
5月前
|
算法 测试技术 索引
算法-二分查找
算法-二分查找
39 0
|
2月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
2月前
|
存储 算法 Java
深入算法基础二分查找数组
文章深入学习了二分查找算法的基础,通过实战例子详细解释了算法的逻辑流程,强调了确定合法搜索边界的重要性,并提供了Java语言的代码实现。
深入算法基础二分查找数组
|
2月前
|
算法
【算法】二分查找——二分查找
【算法】二分查找——二分查找
|
3月前
|
算法
【算法】二分查找(整数二分和浮点数二分)
算法学习——二分查找(整数二分和浮点数二分)
32 0
【算法】二分查找(整数二分和浮点数二分)
|
4月前
|
存储 算法 C语言
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
|
4月前
|
机器学习/深度学习 算法 索引
数据结构算法--1 顺序查找二分查找
**顺序查找时间复杂度为O(n)**,适合无序列表,可以通过`enumerate`或直接遍历索引来实现。**二分查找时间复杂度为O(logn)**,适用于有序列表,利用Python中`left`、`right`指针和`mid`点不断缩小搜索范围。效率上二分查找更优。
|
4月前
|
存储 算法 Java
Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。
【6月更文挑战第21天】Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。简单哈希表实现未涵盖冲突解决和删除操作。
43 1
|
4月前
|
算法 搜索推荐 Java
二分查找算法详解及实现
二分查找算法详解及实现
57 2
|
3月前
|
算法 JavaScript
JS 【算法】二分查找
JS 【算法】二分查找
27 0
下一篇
无影云桌面