插值查找,有序表的一种查找方式。插值查找是根据查找关键字与查找表中最大最小记录关键字比较后的查找方法。插值查找基于二分查找,将查找点的选择改进为自适应选择,提高查找效率。
要注意的是:插值查找除了和二分查找一样要求查找表是顺序存储的有序表外,数据元素的关键字在查找表中最好均匀分布,这样,就可以按比例插值。
基本思路: 插值查找的大体思路和二分查找是一样的,只是不再是递归的从序列的mid进行划分,而是将原来的:
替换为:(相当于将原来的1/2替换为一个平均变化率)
简单来说: 就是将二分查找的查找比例由1/2变化为
举例:
有一有序序列:1,2,3,4…98,99,100
时间: 插值插值的效率与序列的排列有关,在序列独立均匀的分布的情况下,每经过一次比较,待查找区间宽度n缩 小至 2 \sqrt{2} 2 ,设k次查找后区间宽度<2,k即为复杂度。由前可得 N ( 1 / 2 ) k N^{(1/2)^k} N(1/2)k <2 ,恒等变形,解出k即得复杂度: l o g l o g 2 n {log_log_2n} loglog2n
空间: 插值插值无需额外开辟空间,所以空间复杂度为O(1)。
算法 | 平均时间 | 最好情形 | 最坏情形 | 空间复杂度 | 备注 |
---|---|---|---|---|---|
插值查找 | O( l o g l o g 2 n {log_log_2n} loglog2n) | O(1) | O( l o g l o g 2 n {log_log_2n} loglog2n) | O(1) | 待查表是有序表时才可以使用,并且最好为均匀排列 |
/**
* 插值查找,要求数组有序
* @author dankejun
* @create 2020-05-03 12:08
*/
public class InsertSearch {
public static void main(String[] args) {
int[] arr = new int[100];
for (int i = 0; i < arr.length; i++) {
arr[i] = i + 1;
}
//System.out.println(Arrays.toString(arr));
int index = insertSearch(arr, 0, arr.length - 1, 27);
System.out.println("待查找元素下标为:" + index);
}
/**
*
* @param arr 传入的数组
* @param left 左边下标
* @param right 右边下标
* @param value 要查找的值
* @return 如果找到,返回对应的下标,如果没有找到,返回-1
*/
public static int insertSearch(int[] arr, int left, int right, int 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]);
System.out.println("mid=" + mid);
int midVal = arr[mid];
if (value > midVal) {
return insertSearch(arr, mid + 1, right, value);
} else if (value < midVal) {
return insertSearch(arr, left, mid, value);
} else {
return mid;
}
}
}