插值查找原理:
插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找
将折半查找中的求mid索引的公式,low表示左边索引 left , high表示右边索引 right, key就是待查找的值 value
int mid = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]); //插值索引
例如:对于有序序列 {1,2,…,100},查找数值 1 :
①如果使用二分查找
int mid = (left + right) / 2;
则一共需要查找7次才能找到数值 1 所在的位置;
②如果使用插值查找
int mid = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
对于序列1~100,要查找数值 1,则value = 1,left = 0,right = 99,则mid = 0 + (99 - 0) * (1 - 1) / (100 - 1) = 0,则只需要查找1次就能找到待查找的位置;效率明显提高;
代码实现
//插值查找算法,也是要求序列是有序的
/**
* @param arr 待查找的数组
* @param left 左边索引
* @param right 右边索引
* @param value 带查找的值
* @return 如果找到,则返回对应的下标,如果找不到,就返回-1
*/
public static int insertValueSearch(int[] arr,int left, int right, int value) {
//为了防止 mid 越界,所以需要加上两个条件,需要比较value的值和数组的第一个和最后一个元素的值的大小
if (left > right || value < arr[0] || value > arr[arr.length - 1]) {
return -1;
}
int mid = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
if (value > arr[mid]) {
left = mid + 1;
return insertValueSearch(arr,left,right,value);
}
else if (value < arr[mid]) {
right = mid - 1;
return insertValueSearch(arr,left,right,value);
}
else {
return mid;
}
}
插值查找的注意事项:
1、对于数据量比较大,关键字分布比较均匀的查找表来说,采用插值查找,速度比较快
2、关键字分布不均匀的情况下,该方法不一定要比折半查找好