我们学习了二分查找,本节我们来学习插值查找算法,在学习之前我们先来看看二分查找的不足之处
假设我有一组有序的线性表{1,2,3,4,...,20},我们来利用二分查找来找1,看看它会经过几次能找到我们的1代码如下:
/**
*
* @param arr 要查找的数组
* @param left 左边下标
* @param right 右边下标
* @param findVal 要查找的数
*/
public static int binarySearch(int[] arr,int left,int right,int findVal){
System.out.println("调用的次数!!");
//定义中间变量索引并初始化
int mid = (left + right) /2;
//获取中间变量索引对应的下标
int midVal = arr[mid];
//如果找不到,我们结束递归的条件是left > right
if (left > right){
return -1;
}
//进行查找
if (findVal >midVal){ //表示要查找的值在右边,我们递归处理
//说明: 右边查找我们需要改变左边的下标也就是从 mid+1处开始去递归处理结果
return binarySearch(arr,mid +1,right,findVal);
}else if (findVal < midVal) {
//表示要查找的值在左边,我们递归处理
//说明: 左边查找我们需要改变右边的下标也就是从 left - mid-1之间去递归处理结果
return binarySearch(arr,left,mid -1,findVal);
}else {
return mid;
}
}
- 测试代码
public static void main(String[] args) {
int [] arr = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
int result = binarySearch(arr, 0, arr.length - 1, 1);
System.out.println("result ="+result);
-
来看测试结果:
测试结果.png
从上述的结果图中我们发现,为了找1我们递归了4次才找到的,其实这样的话看来二分查找的效率不是很高,那么有没有一种自适应的方式来快速的帮助我们完成查找的这个操作,答案是有的,也就是我们本节学习的插值查找,简单的来介绍下什么是插值查找算法?
插值查找算法介绍
其实插值查找算法的过程跟二分查找的类似,二者唯一的区别是插值查找每次都能从自适应的mid(中间值或者是中间索引或者是下标)处开始找,还记的我们在二分查找算法中求解mid的过程?
- 二分查找mid的计算公式
mid = (left+right)/2 = left + 1/2(right -left)
其中left表示左边下标,right表示右边下标,我们需要对该上述的计算过程进行改造如下:
mid = left +(right -left)*(findVal -arr[left])/(arr[right] - arr[left])
其中 findVal表示我们要查找的数;arr[left]表示左边索引对应的数;arr[right]表示右边索引对应的数,这就是插值查找算法mind索引的计算公式,这里我们简单的自测下它到底有多快,假设我有从1-100的数组,我们来测试一下:
- 需求1: 从arr[1,2,3,...,100]中查找1,代入上述的公式来计算下
int mid = 0+(99-0)* (1- arr[0]) / (arr[99] - arr[0]) =
= 0 +99 *(1- 1) /(100 - 1) = 0
计算的结果为0,也就是arr[0] = 1.发现我们只需要一次就可以了找到1这个数,再来测试下100这个过程,同样计算如下:
int mid = 0 +(99 - 0) * (100 - arr[0]) / (arr[99] - arr[0]) =
0+ 99 * (100 - 1) /(100 -1) = 0 + 99 = 99
计算结果可以看出为99,同样也需要1次就可以找到,这里也就是 arr[99] = 100,看完了过程我们用代码的方式来实现下从1-100的数组中去找的这个过程
代码实现
//插值查找方法
//说明:插值查找算法也是有序的
/**
*
* @param arr 待查找的数组
* @param left 左边下标
* @param right 右边下标
* @param findVal 要查找的值
* @return
*/
public static int insertValSearch(int[] arr,int left,int right,int findVal){
System.out.println("查找的次数--");
//判断
if (left > right|| findVal <arr[0] || findVal> arr[arr.length -1]){
return -1;
}
//首先我们计算出中间索引mid
int mid = left +(right - left) * (findVal - arr[left]) /(arr[right] -arr[left]);
//初始化mid索引所对应的值
int midVal = arr[mid];
if (findVal > midVal){ //表示从mid的右边开始递归找
return insertValSearch(arr,mid+1,right,findVal);
}else if (findVal < midVal){
return insertValSearch(arr,left,mid -1,findVal);
}else {
//表示找到
return mid;
}
}
- 来看测试代码
public class InsertValueSearch {
public static void main(String[] args) {
int [] arr = new int[100];
for (int i = 0; i < 100 ; i++) {
arr[i] = i +1;
}
//System.out.println(Arrays.toString(arr));
int indexResult = insertValSearch(arr, 0, arr.length-1, 1);
System.out.println("result = "+indexResult);
}
- 测试结果如下
![](https://img.haomeiwen.com/i3711017/d47e20431e832866.png)
我们发现通过一次就能找到1了,我们来测试下二分查找需要几次,测试结果如下:
![](https://img.haomeiwen.com/i3711017/6c348aabed11f17f.png)
从测试的结果来看,二分需要6次,在一次的从这里体现了插值查找的优点,那么关于插值查找算法的学习就到这里了...
网友评论