查找算法之插值查找

简介:

  插值查找需要在有序数组的前提下进行,与二分查找的原理一样,只不过二分查找寻找中轴的方式是折半 (left + right) / 2,而插值查找是 left + (right - left) * (value - arr[left]) / (arr[right] - arr[left])。

  如果有序数组的值分布比较均匀,那么插值查找对于中轴的定位更为准确,查找所需要递归的次数更少,效率也会更高(比如等差数列,往往只需要一次就能找到与目标值相等的中轴值)。但是因为中轴下标的确定与输入的目标值相关,所以要首先判断目标值是否在数组值的范围里面(数组最小值<=目标值<=数组最大值),否则极有可能数组越界。对于数组里全是相同值的情况要另外做处理,否则会导致寻找中轴的公式分母为0。

代码:

复制代码
 1     /**
 2      * 插值查找
 3      * @param arr   从小到大的有序数组
 4      * @param left  左索引
 5      * @param right 右索引
 6      * @param value 目标值
 7      * @return
 8      */
 9     public static List<Integer> insertSearch(int[] arr, int left, int right, int value) {
10         //数组为空不查找
11         if (arr == null || arr.length == 0) {
12             return Collections.emptyList();
13         }
14         //在数组中没有找到目标值
15         if (left > right) {
16             return Collections.emptyList();
17         }
18         //数组中没有目标值,防止数组越界
19         if (value < arr[left] || value > arr[right]) {
20             return Collections.emptyList();
21         }
22         //与目标值相同的下标
23         ArrayList<Integer> result = new ArrayList<>(arr.length);
24         //数组全是相同的值(防止计算pivot时,分母为0)
25         if (arr[left] == arr[right]) {
26             //到了这里,如果数组全是相同的值,那么必然是等于目标值
27             for (int i = left; i <= right; i++) {
28                 result.add(i);
29             }
30             return result;
31         }
32         //计算自适应的中轴 公式:pivot = left + (value-arr[left])/(arr[right]-arr[left]) * (right-left)
33         //因为(value-arr[left])/(arr[right]-arr[left])很可能是一个小于1的数,转为int是0。那么pivot总是为left,
34         //没有意义,所以调整为pivot = left + (right-left)*(value-arr[left])/(arr[right]-arr[left])
35         int pivot = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
36         if (value < arr[pivot]) {
37             //如果目标值小于中轴值,往左边找
38             return insertSearch(arr, left, pivot - 1, value);
39         } else if (value > arr[pivot]) {
40             //如果目标值大于中轴值,往右边找
41             return insertSearch(arr, pivot + 1, right, value);
42         } else {
43             //如果目标值与中轴值相等,向左向右循环将紧挨着的,与目标值也相等的那些下标全找到
44             int temp = pivot;
45             //向左找
46             while (temp >= 0 && arr[temp] == value) {
47                 result.add(temp);
48                 temp--;
49             }
50             //向右找
51             temp = pivot + 1;
52             while (temp <= arr.length - 1 && arr[temp] == value) {
53                 result.add(temp);
54                 temp++;
55             }
56         }
57         return result;
58     }
复制代码

 

posted @   Java厨师长  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示