1. 程式人生 > 實用技巧 >插值查詢演算法

插值查詢演算法

插值查詢演算法原理

  • 插值查詢演算法類似於二分查詢,不同的是插值查詢每次從自適應mid處開始查詢
  • 將折半查詢中的求mid索引的公式 \(mid=\frac{left+right}{2}=low+\frac{1}{2}(left+right)\) 改成 \(mid=low+\frac{findVal-arr[left]}{arr[right]-arr[left]}(right-left)\)

舉例說明插值查詢演算法

程式碼實現

程式碼實現返回查詢到的第一個索引

public class InsertValSearch {
    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000, 1234};
        int index = insertValSearch(arr, 0, arr.length - 1, 1000);
        System.out.println("index = "+index);
    }
    /**
     * @param arr     陣列
     * @param left    左邊的下標
     * @param right   右邊的下標
     * @param findVal 待查詢的值
     * @return 返回找到的第一個索引
     */
    private static int insertValSearch(int[] arr, int left, int right, int findVal) {
        if (findVal < arr[left] || findVal > arr[right] || left > right) {
            return -1;
        }
        int mid = left + (findVal - arr[left]) / (arr[right] - arr[left]) * (right - left);
        if (findVal < arr[mid]) {
            return insertValSearch(arr, left, mid - 1, findVal);
        } else if (findVal > arr[mid]) {
            return insertValSearch(arr, mid + 1, right, findVal);
        }else {
            return mid;
        }
    }
}

返回查詢到的所有下標

public class InsertValSearch {
    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000,1000, 1234};
        List<Integer> indexList = insertValSearch2(arr, 0, arr.length - 1, 1000);
        System.out.println("indexList = "+indexList);
    }

    /**
     * @param arr     陣列
     * @param left    左邊的下標
     * @param right   右邊的下標
     * @param findVal 待查詢的值
     * @return 返回找到的所有值的下標
     */
    private static List<Integer> insertValSearch2(int[] arr, int left, int right, int findVal) {
        if (findVal < arr[left] || findVal > arr[right] || left > right) {
            return new ArrayList<Integer>();
        }
        int mid = left + (findVal - arr[left]) / (arr[right] - arr[left]) * (right - left);
        List<Integer> indexList = new ArrayList<>();
        if (findVal < arr[mid]) {
            return insertValSearch2(arr, left, mid - 1, findVal);
        } else if (findVal > arr[mid]) {
            return insertValSearch2(arr, mid + 1, right, findVal);
        } else {
            // 這裡需要返回所有的下標,所以需要對找到的一個下標進行向左和向右的遍歷
            int temp = mid - 1;
            while (true) { // 向左遍歷
                if (temp < 0 || arr[temp] != findVal) {
                    break;
                }
                indexList.add(temp);
                temp -= 1;
            }
            indexList.add(mid);
            temp = mid + 1;
            while (true) { //向右遍歷
                if (temp > arr.length - 1 || arr[temp] != findVal) {
                    break;
                }
                indexList.add(temp);
                temp += 1;
            }

            return indexList;
        }
    }