插值查找

176 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第二十二天,点击查看活动详情

前言:上一文大家了解到了二分查找算法,接下来给大家详细解说插值查找并温故一下二分查找的思路~

二分查找 / 折半查找

  • 必须是顺序的数组,若是无序的,则需要先排序(小到大 / 大到小)

思路

(以下是排序已为由小到大)

  1. 首先确定该数组的中间下标

    • mid = (left + right)/ 2
  2. 然后让需要查找的数 findValue 和 arr[mid] 进行比较

    1. findValue > mid[arr] :说明要查找的数在 mid 的右边,应该向右查找(向右递归查找)
    2. findValue < mid[arr] :说明要查找的数在 mid 的左边,应该向左查找(向左递归查找)
    3. findValue = mid[arr] :说明已经找到,则返回
  3. 退出递归

    1. 找到目标退出递归
    2. 找不到退出递归 (==left > right==)

插值查找

  1. 也是得用在==有序数组==上

  2. 插值查找每次从自适应mid处开始查找

  3. 将折半查找中的求mid 索引的公式 , low 表示左边索引left, high表示右边索引right. key 就是 findValue

    image-20220906222633930

    int mid = low + (high - low) * (key - arr[low]) / (arr[high] - arr[low]) ;

    对应前面的代码公式: int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left])

特点

  • 可以一次就能查找想要的结果
  • 与二分查找相比, 想过肯定的好很多的

使用场景

  • 对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找, 速度较快
  • 关键字分布不均匀的情况下,该方法不一定比折半查找要好
/**
 * @author Kcs 2022/9/6
 */
public class InsertValueSearch {
    public static void main(String[] args) {
        //1 ~ 100 数组
        int[] array = new int[100];
        for (int i = 0; i < 100; i++) {
            array[i] = i + 1;
        }
        int index = insertValueSearch(array, 0, array.length - 1, 50);
        System.out.println("index = " + index);
​
    }
​
    /**
     * 插值查找算法
     * @param array 查找的数组
     * @param left 左边 索引
     * @param right 右边索引
     * @param findValue 查找的值
     * @return index
     */
    public static int insertValueSearch(int[] array, int left, int right, int findValue) {
        System.out.println("查找了!!!!");
​
        //不符合,则退出 优化查找,防止mid越界。自适应的查找
        if (left > right || findValue < array[0] || findValue > array[array.length - 1]) {
            return -1;
        }
        //求出mid
        int mid = left + (right - left) * (findValue - array[left]) / (array[right] - array[left]);
        //中间的值
        int midValue = array[mid];
​
        if (findValue > midValue) {
            //向右递归查找
            return insertValueSearch(array, mid + 1, right, findValue);
        } else if (findValue < midValue) {
            //向左递归查找
            return insertValueSearch(array, left, mid - 1, findValue);
        } else {
            //相等
            return mid;
        }
    }
}