数据结构和算法九-二分查找算法

1 算法简介

二分查找思路比较简单,对于一个有序数组,先比价目标元素和中间元素,如果比中间元素小则在左半部分查找;如果比中间元素大则在右半部分查找。

2 代码实现

public class BinarySearch {

    public Integer search(Integer[] arrs, int num) {
        return binarySearch(arrs, 0, arrs.length - 1, num);
    }

    private Integer binarySearch(Integer[] arrs, int left, int right, int num) {
        if(left > right) {
            return -1;
        }
        int mid = getMid(arrs, left, right, num);
        if (mid > right) {
            return -1;
        }
        if(arrs[mid] < num) {
            return binarySearch(arrs, mid + 1, right, num);
        }else if(arrs[mid] > num) {
            return binarySearch(arrs, 0, mid - 1, num);
        }else {
            // 返回下标较小的元素
            while (mid >= 0 && arrs[mid] == num) {
                mid --;
            }
            return mid + 1;
        }
    }

    protected int getMid(Integer[] arrs, int left, int right, int num) {
        return (left + right) / 2;
    }

}

3 算法优化

3.1 插值查找

上述方法选取mid下标的时候总是选择的中间的元素。如果我们查一个有序数组中最大的或者最小的那个元素需要多次折半才能查到。这里选取mid下标的时候做一个优化,根据目标元素和最大最小值关系来选取,代码如下

public class InterpolationSearch extends BinarySearch {
    @Override
    protected int getMid(Integer[] arrs, int left, int right, int num) {
        return left + (num - arrs[left]) / (arrs[right] - arrs[left]) * (right - left);
    }
}

3.2 斐波那契查找

普通二分查找是通过除法不断减半缩小搜索范围,这里我们用斐波那契数列来缩小范围。
举个例子,例如数组大小是 100,比它大的最小斐波那契数是 144,斐波那契数列如下:0 1 1 2 3 5 8 13 21 34 55 89 144
1)我们记 f(n) = 144,f(n-1) = 89, f(n-2) = 55。
2)选取比较值arrs[89],如果目标值比比较值小则在0-89范围查找;否则在89-100范围查找
3)如果在左边,令n = n-1;否则令n = n-2
4)递归上述过程即可完成查找。
斐波那契查找好处是用简单的加减运算代替了二分查找的除法运算,提高查找速度
代码实现

public class FibonacciSearch {

    private int size = 46;

    private int[] f = new int[size];

    public FibonacciSearch() {
        // 初始化fibonacci数列
        f[0] = 0;
        f[1] = 1;
        for(int i = 2; i < size; i ++) {
            f[i] = f[i - 1] + f[i - 2];
        }
    }

    public Integer search(Integer[] arrs, int num) {
        new BaseMergeSort().sort(arrs);
        int k = 0;
        // 在斐波那契数列找一个等于略大于查找表中元素个数的数F[k]
        while (f[k] < arrs.length) {
            k ++;
        }

        int lo = 0;
        int hi = arrs.length - 1;
        while (lo <= hi && k > 0) {
            int mid = Math.min(lo + f[k - 1], arrs.length - 1);
            if (arrs[mid] < num) {
                // 在右侧查找
                lo = mid + 1;
                k -= 2;
            }else if (arrs[mid] > num) {
                // 在左侧查找
                hi = mid - 1;
                k --;
            }else {
                return mid;
            }
        }
        return -1;
    }

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值