数据结构和算法学习日记——二分法查询

查找算法种类

  • 顺序查找
  • 二分查找/折半查找
  • 插值查找
  • 斐波那契查找

在这里,顺序查找和普通的二分发查找不做概述。

插值查找

插值查找类似于二分法,不同的是插值查找就是每次自适应mid处查找。

理解关键程序

int mid = left + (right - left) * (val - arr[left]) / (arr[right] - arr[left]);

如上述一行程序:

left:数组查询时最左边的索引

right - left:数组查询时要查询的全部数字个数

(val - arr[left]) / (arr[right] - arr[left]):其中val是要查找的值,因为插值查找类似二分法查找,因此查找的数组皆是按顺序排列的。(此处默认数组是按从小到大排序)。如果将(arr[right] - arr[left])看成要查询部分的总长度,而``(val - arr[left])`可以看作查询的值距离左边的长度,将两者相除,估算出要查询值位于总数组的那一部分,进而估算mid。

可以如下图进行理解:

1569756996897
代码实现
public static int search(int[] arr, int left, int right, int val) {

    if(left > right || val < arr[left] || val > arr[right]) {
        return -1;
    }

    int mid = left + (right - left) * (val - arr[left]) / (arr[right] - arr[left]);

    if(val < arr[mid]) {
        return search(arr, left, mid - 1, val);
    } else if (val > arr[mid]) {
        return search(arr, mid + 1, right, val);
    } else {
        return mid;
    }
}

斐波那契查找

斐波那契数列有一个特性:在斐波那契数列中,随这索引不断向后,数列中前一个值与后一个值的比会无限接近于黄金分割,即0.618

原理

根据查找数组的长度匹配已经生成的斐波那契数列,早到查询数组的黄金分割线,该线所在的位置是mid。其余与二分法类似(默认数组按从小到大排序)

mid的计算方法

斐波那契数列: fib[k] = fib[k - 1] + fib[k - 2]

假设fib[k]是查询数组的长度,因为fib[k - 1] / fib[k] 随着k的无限增大,该公式无限接近于黄金分割,因此mid出现在fib[k - 1]处。

fib[k] = fib[k - 1] + fib[k - 2]转换为:fib[k] - 1 = (fib[k - 1] - 1) + (fib[k - 2] - 1) + 1, 如果将fib[k] - 1看作查询数组的长度,那么mid = low + fib[k - 1] - 1

算法图示
1569758009534
算法实现:
	public static int search2(int[] arr, int val) {
		
		int low = 0;
		int high = arr.length - 1;
		// 构建斐波那契数列
		int[] fib = new int[20];
		fib[0] = 1;
		fib[1] = 1;
		for(int i = 2; i < fib.length; i++) {
			fib[i] = fib[i - 1] + fib[i - 2];
		}
		
		// 利用斐波那契数列,选取中值
		int k = 0;
		while(high > fib[k] - 1) {
			k++;
		}
		
		// 填充0的部分
		int[] temp = Arrays.copyOf(arr, fib[k]);
		for(int i = high + 1; i < temp.length; i++) {
			temp[i] = arr[high];
		}
		
		
		// 实现二分法
		while(low <= high) {
			
			int mid = low + fib[k - 1] - 1;
			
			if(val < arr[mid]) {
				high = mid - 1;
				k--;
			} else if(val > arr[mid]) {
				low = mid + 1;
				k -= 2;
			} else {
				if(mid > high) {
					return high;
				} else {
					return mid;
				}
			}
			
		}
		
		return -1;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值