三种二分查找的实现方法与分析

1.介绍

二分查找也称折半查找(Binary Search),它是查找算法中较为基础的一种算法,是学习算法入门的好例子,也是一种效率较高的查找方法。但是,二分查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。对原始数据的结构要求较高

2.实现方法及其分析

1.二分查找(基础版)

public static int BinarySearch(int[] arr,int target){
        int i = 0;int j = arr.length - 1; //定义两个指针分别指向数组的两端
        while (i <= j){                   //当两个指针之间还有元素时表示还没找完
            int m = (i+j) >>> 1;//(i+j)/2;              //每次取得两个指针中间的元素,并分别与目标元素进行比较(推荐使用无符号右移位运算 >>> 1 )
            if(arr[m] < target){          //若目标元素大,则起始指针指向中间结点+1的地方,下次查找只需查找后半部分
                i = m+1;
            } else if (arr[m] > target) {//若目标元素小,则末尾指针指向中间结点-1的地方,下次查找只需查找前半部分
                j = m-1;
            }else{
                return m;                //若中间节点的值刚好等于目标元素的值,则直接返回该index
            }
        }

在上述的二分查找基础版方法中,我们先定义了两个“指针”,分别指向数组的前后两端。

然后在while循环中求出两个指针的中间位置(小数向下取整),再比较target与该位置元素的大小

从而决定缩小左边界还是右边界,循环往复,直至刚好与target值相等返回对应的数组下标即为与target元素相等的数组元素的位置,若找不到该元素则返回-1。

2.二分查找(左闭右开版)

public static int BinarySearch(int []arr,int target){
        int i = 0;
        int j = arr.length;  //改动一
        while (i < j){       //改动二
            int m = (i + j) >>> 1;
             if (arr[m] < target){
                 i = m;      //改动三
             } else if (target < arr[m]) {
                 j = m - 1;
             } else if (target == arr[m]) {
                 return m;
             }
        }
        return -1;
    }

该算法在上述的基础版的基础上做了三个改动,使右侧指针指向的元素不可能为目标元素(相当于集合的开区间)

3.二分查找(平衡版)

public static int BinarySearch(int[] arr,int target){
        int i = 0;
        int j = arr.length;
        while (1 < (j - i)){
            int m = (i + j) >>> 1;
            if(target < arr[m]){
                j = m;
            }else {
                i = m;
            }
            if(target == arr[i]){
                return i;      //出循环的时候两个指针之间没有元素,直接比较i对应的元素(j只是边界不参与比较),有的话i对应的就是结果,无的话直接不成立,最后返回-1
            }
        }

        return -1;
    }

在上述的两种二分查找的实现方式中,我们不难发现,在while循环中的if语句比较中“<”和“>”的比较总是有先后顺序,这导致了当我们查找的target元素在数组中的位置偏左或偏右时执行的比较次数差异较大,总有一方的比较次数较快/较慢,为了解决这种不平衡,设计了二分查找的平衡版本

在平衡版本中,target==目标元素的比较语句被放在了while循环之外,这样循环内的“<”,“>”比较可以用if-else语句来执行(只需要一次比较),因此target元素无论在数组的哪边所需要进行的比较都是相近的,但同时由于 target==目标元素的比较语句被放在了while循环之外,所以循环每次都会被执行满,不会提前跳出整体运行速度一般。

3.Java中提供的二分查找API

在Java中内置了二分查找的API,在

Arrays.binarySearch(int [] arr;int target);中

查看其源码

private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

观察发现其使用的是二分查找的基础版,有差别的是当需要找的元素不存在时返回 -(*插入点 - 1)。

*插入点:在该点插入target元素,其整个数组保持有序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

享受学习每一天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值