二分查找优化

二分查找在顺序查找时时间复杂度为O(logn),是一种高效的查找算法

传统二分查找

public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        int i = binarySearch(arr, 0);
        System.out.println("i = " + i);
    }

    public static int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;

        while (left < right) {
            int mid = (left + right) / 2;

            if (arr[mid] > target) right = mid - 1;
            else if (arr[mid] < target) left = mid + 1;
            else return mid;
        }

        return -1;
    }
}

存在的问题

二分查找的流程

  • 找到数组中点的位置
  • 判断待查找的元素在中点值的左面还是右面
    • 在中点值的左面时就让右边界等于中点
    • 在中点值的右面时就让左边界等于中点 + 1
  • 重复此过程,直到待查找的值等于终点值时退出,否则返回-1

这里可以看到,由于查找时是从中点进行比较的,如果数组中的元素为1-1000时,待查找的值为10,此时再从中点开始查找时,二分查找的性能就远不如顺序查找来的快。

解决办法就是每次不是从中点进行查找,而是根据key来确定key右面的区间,从这个右区间进行查找。因此,就有一个确定这个区间右节点的公式

m i d = l e f t + k e y − a r r [ l e f t ] a r r [ r i g h t ] − k e y × ( r i g h t − l e f t ) mid = left + \frac{key - arr[left]}{arr[right] - key} \times (right - left) mid=left+arr[right]keykeyarr[left]×(rightleft)

此种查找方式又称之为插值查找,但是此种方式适用于查找的序列非常大,而且数据分布又比较均匀的情况。

优化后的代码

public class BinarySearchOptimize {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        int i = binarySearch(arr, 2);
        System.out.println("i = " + i);
    }

    public static int binarySearch(int[] arr, int key) {
        int left = 0;
        int right = arr.length - 1;
        while(left < right) {
            int mid = left + (key - arr[left]) / (arr[right] - key) * (right - left);

            if(arr[mid] > key) {
                right = mid;
            } else if(arr[mid] < key) {
                left = mid + 1;
            } else {
                return mid;
            }
        }

        return -1;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值