美文网首页
二分查找的实现及使用场景

二分查找的实现及使用场景

作者: 文景大大 | 来源:发表于2020-10-15 20:18 被阅读0次

一、二分查找的实现

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

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

二分查找过程示意图

使用代码实现如下:

    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;
        }
    

四、总结

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

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

相关文章

  • 二分查找的实现及使用场景

    一、二分查找的实现 对于给定的已经有序的数列,我们需要在该数列中查找是否存在某个元素。 每次都与数列最中间的元素进...

  • 二分法的简单使用问题

    使用场景 开发思路 代码实现规则获取地址转换二分法查找设计错例问题点代码调整 附 使用场景 根据访问日志的ip地址...

  • 二分查找算法--Python语言描述

    当列表的数据是有序的情况下, 使用二分查找算法是非常高效的, 以下使用两种方式实现了二分查找。 二分查找的一般算法...

  • 简单算法

    冒泡排序: while 实现的二分查找: 递归实现二分查找:

  • golang循环递增数组查找值

    循环递增数组查找值 golang 1.实现要求 在循环递增数组中查找某个值 2.实现方法 使用二分法实现查找 使用...

  • LeetCode 数组专题 1:二分查找

    二分查找法 说明:二分查找法在代码实现上有模板方法,一定要掌握。 1、二分查找法的使用前提:数组一定要是排好序的,...

  • 算法之二分查找

    二分查找 二分查找是著名、高效并有应用广泛的查找算法。 二分常规实现 1.循环实现 下面我用python语言实现循...

  • 二分搜索难点分析

    能使用二分搜索的前提是数组已排序。 二分查找的使用场景:(1)可转换为find the first/last po...

  • 分治算法(swift二分法排序递归实现)

    二分查找 1、二分查找(Binary Search) 2、二分查找的基本思想 swift算法实现

  • 二分查找

    网上找到的图片便于理解 二分查找递归实现与循环实现代码: /** 二分查找 1.二分查找又称折半查找,它是一种效率...

网友评论

      本文标题:二分查找的实现及使用场景

      本文链接:https://www.haomeiwen.com/subject/eegopktx.html