java常见算法插值查找


插值查找算法是在有序数组中查找指定元素的一种算法,与二分查找类似,但是插值查找算法的时间复杂度更优秀。

Java中的插值查找算法可以通过以下代码实现:

public static int interpolationSearch(int[] arr, int key) {
    int low = 0, high = arr.length - 1;
    while (low <= high && key >= arr[low] && key <= arr[high]) {
        int pos = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low]);
        if (arr[pos] == key) {
            return pos;
        } else if (arr[pos] < key) {
            low = pos + 1;
        } else {
            high = pos - 1;
        }
    }
    return -1;
}

其中,arr表示有序数组,key表示要查找的元素。该算法的核心思想是根据元素值的大小在数组中进行插值,从而确定要查找的元素在数组中的位置。

插值查找算法与二分查找算法的不同之处在于,它不是每次都将数组的中间位置作为比较的对象,而是根据要查找的元素的值,计算出一个更加接近要查找的元素的位置,从而提高查找效率。

具体来说,插值查找算法中,计算要查找的元素的位置 pos 的公式为:

QQ图片20230515074854.png

其中,low、high分别为数组的起始位置和结束位置,key为要查找的元素值,arr为有序数组。

通过该公式计算出 pos 的位置后,将 arr[pos] 与要查找的元素值 key 进行比较,如果相等则返回 pos,否则根据比较结果来更新 low 或 high 的位置,继续进行查找,直到找到要查找的元素或者数组已经遍历完毕,返回 -1 表示查找失败。

需要注意的是,插值查找算法适用于分布比较均匀的有序数组,对于分布不均匀的数组,可能会出现效率不如二分查找的情况。

插值查找算法的时间复杂度为 O(log log n),与二分查找算法相比,它对于分布比较均匀的有序数组,可以提高查找效率,但对于分布不均匀的数组,可能会导致效率不如二分查找。

在实际应用中,插值查找算法可以用于需要高效查找的场景,例如数据库索引、搜索引擎等。同时,它也可以用于求解一些函数的零点问题,例如求解 f(x)=0 的根,可以将函数值作为数组中的元素,使用插值查找算法来查找函数值为 0 的位置。

另外,需要注意的是,在使用插值查找算法时,需要确保数组是有序的,否则无法得到正确的查找结果。同时,也需要注意数组下标的范围,避免出现数组下标越界的情况。

下面给出一个简单的示例,展示如何使用插值查找算法在一个有序数组中查找指定元素:

public class InterpolationSearchExample {
    public static void main(String[] args) {
        int[] arr = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
        int key = 12;
        int index = interpolationSearch(arr, key);
        if (index == -1) {
            System.out.println("元素 " + key + " 未找到");
        } else {
            System.out.println("元素 " + key + " 的位置为:" + index);
        }
    }

    public static int interpolationSearch(int[] arr, int key) {
        int low = 0, high = arr.length - 1;
        while (low <= high && key >= arr[low] && key <= arr[high]) {
            int pos = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low]);
            if (arr[pos] == key) {
                return pos;
            } else if (arr[pos] < key) {
                low = pos + 1;
            } else {
                high = pos - 1;
            }
        }
        return -1;
    }
}

在该示例中,首先定义了一个有序数组 arr,然后定义要查找的元素 key 为 12。接着调用 interpolationSearch 方法,在数组 arr 中查找元素 key,并返回它在数组中的位置。最后根据返回的结果输出相应的信息。

执行上述代码,将输出以下结果:

元素 12 的位置为5

这表明元素 12 在数组 arr 中的位置为 5,即数组下标从 0 开始,元素 12 在数组中的位置为第 6 个。

另外,需要注意的是,如果数组中存在重复的元素,插值查找算法可能会返回任意一个匹配的元素的下标。如果需要返回第一个或最后一个匹配的元素的下标,可以在查找到元素的位置后,向前或向后遍历数组,直到找到第一个或最后一个匹配的元素。

下面给出一个示例代码,展示如何在一个有序数组中查找第一个匹配的元素:

public class InterpolationSearchExample {
    public static void main(String[] args) {
        int[] arr = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 20};
        int key = 20;
        int index = firstInterpolationSearch(arr, key);
        if (index == -1) {
            System.out.println("元素 " + key + " 未找到");
        } else {
            System.out.println("元素 " + key + " 的第一个位置为:" + index);
        }
    }

    public static int firstInterpolationSearch(int[] arr, int key) {
        int low = 0, high = arr.length - 1;
        int result = -1;
        while (low <= high && key >= arr[low] && key <= arr[high]) {
            int pos = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low]);
            if (arr[pos] == key) {
                result = pos;
                high = pos - 1;
            } else if (arr[pos] < key) {
                low = pos + 1;
            } else {
                high = pos - 1;
            }
        }
        return result;
    }
}

在该示例中,数组 arr 中包含多个重复的元素 20,然后定义要查找的元素 key 为 20。接着调用 firstInterpolationSearch 方法,在数组 arr 中查找第一个匹配的元素 key,并返回它在数组中的位置。最后根据返回的结果输出相应的信息。

执行上述代码,将输出以下结果:

元素 20 的第一个位置为9

这表明元素 20 在数组 arr 中的第一个匹配位置为 9,即数组下标从 0 开始,元素 20 在数组中的位置为第 10 个。

如果需要在一个有序数组中查找最后一个匹配的元素,可以使用类似的方式实现,如下所示:

public class InterpolationSearchExample {
    public static void main(String[] args) {
        int[] arr = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 20};
        int key = 20;
        int index = lastInterpolationSearch(arr, key);
        if (index == -1) {
            System.out.println("元素 " + key + " 未找到");
        } else {
            System.out.println("元素 " + key + " 的最后一个位置为:" + index);
        }
    }

    public static int lastInterpolationSearch(int[] arr, int key) {
        int low = 0, high = arr.length - 1;
        int result = -1;
        while (low <= high && key >= arr[low] && key <= arr[high]) {
            int pos = low + (key - arr[low]) * (high - low) / (arr[high] - arr[low]);
            if (arr[pos] == key) {
                result = pos;
                low = pos + 1;
            } else if (arr[pos] < key) {
                low = pos + 1;
            } else {
                high = pos - 1;
            }
        }
        return result;
    }
}

在该示例中,数组 arr 中同样包含多个重复的元素 20,然后定义要查找的元素 key 为 20。接着调用 lastInterpolationSearch 方法,在数组 arr 中查找最后一个匹配的元素 key,并返回它在数组中的位置。最后根据返回的结果输出相应的信息。

执行上述代码,将输出以下结果:

元素 20 的最后一个位置为11

这表明元素 20 在数组 arr 中的最后一个匹配位置为 11,即数组下标从 0 开始,元素 20 在数组中的位置为第 12 个。

总之,插值查找算法是一种基于二分查找算法的优化,在大规模、连续的数据中具有较好的性能表现。与二分查找算法相比,插值查找算法的优点在于:对于数据分布比较均匀、数据量比较大的有序数组,可以快速找到目标元素;缺点在于:对于数据分布不均匀、数据量比较小的有序数组,可能导致查找效率低下,甚至比二分查找算法还要慢。

除了插值查找算法,还有其他一些常见的查找算法,如线性查找算法、二分查找算法、哈希查找算法、树形查找算法等等。针对不同的应用场景和数据特征,可以选择不同的查找算法来实现。


原文链接:codingdict.net