在均匀分布的有序数列中,会比二分查找次数少很多
思想跟二分查找一直,都是找到其中一个值,小了往左找,大了往右找
区别是:
- 二分查找,不管查找的值是多少,每次都跟最中间的值比较
- 插值查找也叫自适应查找,会找到比较靠近查找值的一边
代码也跟二分查找差不多,就公式不同,不过因为公式复杂了一些,需要一些判断条件来保证它的正确性
二分查找
public static int binarySearch(int[] arr,int key) {
if(arr == null || key > arr[arr.length-1] || key < arr[0] ) {
return -1;
}
int left = 0;
int right = arr.length-1;
int mid = (left+right)/2;
while(left<=right) {
if(key > arr[mid]) {
left = mid + 1;
}else if(key < arr[mid]) {
right = mid - 1;
}else {
return mid;
}
mid = (left+right)/2;
}
return -1;
}
插值查找
public static int interpolationSearch(int[] arr,int left,int right,int key) {
//这个判断一方面是能把在范围外的数快速return-1,
//另一方面是保证在范围内,也就保证了后面计算公式得到的mid值不会越界,
//也就是保证(key-arr[left])/(arr[right]-arr[left])它的结果范围在[0,1]
if(arr == null || key > arr[right] || key < arr[left] ) {
return -1;
}
//保证arr[right]-arr[left]不为0,否则会发生算术异常
if(arr[right] == arr[left]) {
if(key == arr[left]) {
return left;
}
return -1;
}
//插值公式
int mid = left + (right-left)*(key-arr[left])/(arr[right]-arr[left]);
if(key > arr[mid]) {
left = mid + 1;
}else if(key < arr[mid]) {
right = mid - 1;
}else {
return mid;
}
if(left <= right) {
return interpolationSearch(arr,left,right,key);
}
return -1;
}
测试数组
int[] arr = new int[10000];
arr[0] = 1;
for(int i=1;i<arr.length;i++) {
arr[i] = arr[i-1] + (int)(Math.random()*5);
}
查找次数比较
二分查找次数:9
查找结果index=18
插值查找次数:2
查找结果index=18
==============
二分查找次数:13
查找结果index=0
插值查找次数:1
查找结果index=0
==============
二分查找次数:13
查找结果index=-1
插值查找次数:3
查找结果index=-1
==============
二分查找次数:14
查找结果index=-1
插值查找次数:3
查找结果index=-1
==============
二分查找次数:14
查找结果index=37
插值查找次数:3
查找结果index=37
==============
二分查找次数:13
查找结果index=50
插值查找次数:2
查找结果index=50
==============
二分查找次数:13
查找结果index=24
插值查找次数:2
查找结果index=24
==============
二分查找次数:13
查找结果index=21
插值查找次数:2
查找结果index=21
==============
二分查找次数:13
查找结果index=9
插值查找次数:3
查找结果index=9
==============
二分查找次数:14
查找结果index=-1
插值查找次数:3
查找结果index=-1
==============