c 语言 插值搜索(Interpolation Search)

本文介绍了插值搜索算法,一种针对均匀分布数组优化的搜索方法,利用线性插值确定搜索位置,平均时间复杂度为O(log2(log2n)),在实际搜索中比线性搜索和二分搜索更高效。

        给定一个由 n 个均匀分布值 arr[] 组成的排序数组,编写一个函数来搜索数组中的特定元素 x。 
        线性搜索需要 O(n) 时间找到元素,跳转搜索需要 O(? n) 时间,二分搜索需要 O(log n) 时间。 插值搜索是对实例二分搜索的改进,其中排序数组中的值是均匀分布的。

        插值在一组离散的已知数据点的范围内构造新的数据点。二分查找总是到中间元素去检查。

        另一方面,插值搜索可以根据正在搜索的键的值去不同的位置。例如,如果键的值更接近最后一个元素,则插值搜索很可能从末尾侧开始搜索。为了找到要搜索的位置,它使用以下公式。 

// 公式的思想是
当要搜索的元素更接近arr[hi]时,返回较高的pos值。 
// 当接近 arr[lo] 时值更小
arr[] ==> 需要查找元素的数组
x ==> 要搜索的元素
lo ==> arr[] 中的起始索引
hi ==> arr[] 中的结束索引

        有许多不同的插值方法,其中一种称为线性插值。线性插值采用两个数据点,我们假设为 (x1,y1) 和 (x2,y2),公式为:在点 (x,y) 处。
        该算法的工作原理类似于我们在字典中搜索单词。插值搜索算法改进了二分搜索算法。查找值的公式为:K = 数据-低/高-低。
        K是一个常数,用于缩小搜索空间。在二分查找的情况下,该常数的值为:K=(low+high)/2。

pos 的公式可以推导如下:
        我们假设数组的元素是线性分布的,直线的一般方程:y = m*x + c,y 是数组中的值,x 是其索引。
现在将 lo、hi 和 x 的值代入方程:
arr[hi] = m*hi+c ----(1) 
arr[lo] = m*lo+c ----(2) 
x = m* pos + c ----(3) 
m = (arr[hi] - arr[lo] )/ (hi - lo)
从 (3) x - arr[lo] = m * (pos - lo) 减去 eqxn (2) lo) 
lo + (x - arr[lo])/m = pos 
pos = lo + (x - arr[lo]) *(hi - lo)/(arr[hi] - arr[lo])

算法
除了上面的划分逻辑之外,插值算法的其余部分是相同的。 
        步骤1:在循环中,使用探针位置公式计算“pos”的值。 
        步骤2:如果匹配,则返回该项的索引,并退出。 
        步骤3:如果该项小于arr[pos],则计算左子数组的探针位置。否则,在右侧子数组中计算相同的值。 
        步骤4:重复直到找到匹配项或子数组减少到零。

下面是算法的实现: 

// C program to implement interpolation search
// with recursion
#include <stdio.h>
 
// If x is present in arr[0..n-1], then returns
// index of it, else returns -1.
int interpolationSearch(int arr[], int lo, int hi, int x)
{
    int pos;
    // Since array is sorted, an element present
    // in array must be in range defined by corner
    if (lo <= hi && x >= arr[lo] && x <= arr[hi]) {
        // Probing the position with keeping
        // uniform distribution in mind.
        pos = lo
              + (((double)(hi - lo) / (arr[hi] - arr[lo]))
                 * (x - arr[lo]));
 
        // Condition of target found
        if (arr[pos] == x)
            return pos;
 
        // If x is larger, x is in right sub array
        if (arr[pos] < x)
            return interpolationSearch(arr, pos + 1, hi, x);
 
        // If x is smaller, x is in left sub array
        if (arr[pos] > x)
            return interpolationSearch(arr, lo, pos - 1, x);
    }
    return -1;
}
 
// Driver Code
int main()
{
    // Array of items on which search will
    // be conducted.
    int arr[] = { 10, 12, 13, 16, 18, 19, 20, 21,
                  22, 23, 24, 33, 35, 42, 47 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    int x = 18; // Element to be searched
    int index = interpolationSearch(arr, 0, n - 1, x);
 
    // If element was found
    if (index != -1)
        printf("Element found at index %d", index);
    else
        printf("Element not found.");
    return 0;
}

输出
在索引 4 处找到的元素
时间复杂度:平均情况为O(log 2 (log 2 n)),最坏情况为 O(n) 
辅助空间复杂度: O(1)

在C语言中,折半查找(也称为二分查找)是一种高效的查找算法,适用于**有序数组**。其基本思想是通过将目标值与数组中间元素进行比较,逐步缩小查找范围,从而快速定位目标值的位置。 ### 折半查找的实现方法 以下是一个完整的代码示例,展示了如何在升序数组中使用折半查找: ```c #include <stdio.h> // 定义折半查找函数 int binary_search(int arr[], int size, int target) { int left = 0; int right = size - 1; while (left <= right) { int mid = left + (right - left) / 2; // 避免溢出 if (arr[mid] == target) { return mid; // 找到目标值,返回索引 } else if (arr[mid] < target) { left = mid + 1; // 目标值在右半部分 } else { right = mid - 1; // 目标值在左半部分 } } return -1; // 未找到目标值 } int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 升序数组 int size = sizeof(arr) / sizeof(arr[0]); // 计算数组长度 int target; printf("请输入要查找的目标值: "); scanf("%d", &target); int result = binary_search(arr, size, target); // 调用折半查找函数 if (result != -1) { printf("找到了!目标值位于数组的第 %d 个位置。\n", result); } else { printf("未找到目标值。\n"); } return 0; } ``` ### 代码解析 1. **binary_search函数**:这是核心的折半查找逻辑。 - `left` 和 `right` 分别表示当前查找范围的左右边界。 - `mid` 是中间位置的索引,通过 `left + (right - left) / 2` 来计算,以避免整数溢出问题[^2]。 - 如果 `arr[mid]` 等于目标值,则直接返回该索引。 - 如果 `arr[mid]` 小于目标值,则更新左边界为 `mid + 1`,继续在右半部分查找。 - 如果 `arr[mid]` 大于目标值,则更新右边界为 `mid - 1`,继续在左半部分查找。 - 当 `left > right` 时,说明整个数组中没有目标值,返回 `-1` 表示未找到。 2. **main函数**: - 定义了一个升序数组 `arr`。 - 使用 `sizeof` 计算数组的大小。 - 提示用户输入目标值,并调用 `binary_search` 函数进行查找。 - 根据返回结果输出查找结果。 ### 折半查找的特点 - **时间复杂度**:折半查找的时间复杂度为 $O(\log n)$,比线性查找的 $O(n)$ 更高效。 - **适用条件**:折半查找要求数组必须是**有序的**,否则无法正确工作。 - **稳定性**:折半查找本身不涉及交换操作,因此不会改变相同元素的相对顺序,是一种稳定的查找算法[^5]。 ### 插值查找的优化 如果数据分布较为均匀,可以考虑使用插值查找来进一步优化查找效率。插值查找的基本思想是根据目标值和数组两端值的比例关系来选择分割点,而不是固定取中间点。例如,在字典中查找 "apple" 时,人们通常会直接翻到字母 A 的区域,而不是从中间开始逐页查找。 以下是插值查找的代码实现: ```c #include <stdio.h> int interpolation_search(int arr[], int size, int target) { int left = 0; int right = size - 1; while (left <= right && target >= arr[left] && target <= arr[right]) { int pos = left + ((double)(target - arr[left]) / (arr[right] - arr[left])) * (right - left); if (arr[pos] == target) { return pos; // 找到目标值,返回索引 } else if (arr[pos] < target) { left = pos + 1; // 目标值在右半部分 } else { right = pos - 1; // 目标值在左半部分 } } return -1; // 未找到目标值 } int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 升序数组 int size = sizeof(arr) / sizeof(arr[0]); // 计算数组长度 int target; printf("请输入要查找的目标值: "); scanf("%d", &target); int result = interpolation_search(arr, size, target); // 调用插值查找函数 if (result != -1) { printf("找到了!目标值位于数组的第 %d 个位置。\n", result); } else { printf("未找到目标值。\n"); } return 0; } ``` ### 总结 - **折半查找**是一种高效的查找算法,适用于升序数组。 - **插值查找**在数据分布均匀的情况下,查找效率更高,但需要额外的计算。 - 两者都需要数组是有序的,否则无法保证正确性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hefeng_aspnet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值