欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简单算法——二分查找法

程序员文章站 2022-03-08 23:39:46
...

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

但是,前提是查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

查找过程

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

下面我们测试一下:

/**
     * 二分查找
     * @param arr 元素组
     * @param num 查询数据
     * @return 返回脚标
     */
    public static int binarySearch(int [] arr,int num){

        //起始脚标
            int start = 0;
            //末尾脚标
            int end = arr.length -1;
            while(start <= end){
                //获取中间脚标
                int middleindex = (start+ end)/2;
                //  拿中间位置数据 与传递数据进行比较
                if(num < arr[middleindex]){
                    //如果中间位置数据 大于当前数据 则将end 设置为中间位置减一
                    end = middleindex - 1;
                }else if(num > arr[middleindex]){
                    //如果中间位置数据 大于当前数据 则将start 设置为中间位置加一
                    start = middleindex+1;
                }else {
                    //等于 直接命中 返回脚标
                    return middleindex;
                }
            }

        return -1;
    }

    /**
     * 普通查找
     * @param arr 元素组
     * @param num 查询数据
     * @return 返回脚标
     */
    public static int simpleSearch(int [] arr,int num){
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] == num ){
                return i;
            }
        }
        return -1;
    }
  • 设定起始查询脚标为0,结束脚标为数组长度减一。
  • 将数据进行循环,首次获取中间位置(int 会强制转换成整数型,不用担心除不尽)。
  • 拿中间位置数据 与传递数据进行比较 如果中间位置数据 大于当前数据 则将end 设置为中间位置减一
  • 如果中间位置数据 大于当前数据 则将start 设置为中间位置加一
  • 等于 直接命中 返回脚标

创建一个200000000大小的数组测试一下和普通查询的效率差距:

//创建一个200000000大小的数组

    public static void main(String[] args) {
        int [] arr = new int[200000000];

        for (int i = 0; i < 200000000; i++) {
            arr[i] = i ;
        }

        Arrays.sort(arr);
        Instant startTime = Instant.now();
        int i = binarySearch(arr, 190000000);
        Instant endTime = Instant.now();
        System.out.println(i);
        System.out.println("二分查询:" +Duration.between(startTime,endTime).toMillis()+"ms");

        Instant start = Instant.now();
        int i1 = simpleSearch(arr, 190000000);
        System.out.println(i1);
        Instant end = Instant.now();
        System.out.println("遍历查询:"  + Duration.between(start,end).toMillis()+"ms");
    }
190000000
二分查询:0ms
190000000
遍历查询:82ms

可以看到差距比想象中打的惊人。
因为:二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果xa[n/2],则只要在数组a的右半部搜索x.

时间复杂度无非就是while循环的次数!

总共有n个元素,

渐渐跟下去就是n,n/2,n/4,…n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数

由于你n/2^k取整后>=1

即令n/2^k=1

可得k=log2n,(是以2为底,n的对数)

所以时间复杂度可以表示O(h)=O(log2n)。