小编典典

此插值搜索实现有什么问题?

algorithm

这是Internet上常见的插值搜索算法的C / C
++实现。但是,当与大约100000整数的排序数组一起使用时,中间变量开始生成负数组索引,从而导致分段错误。可能是什么问题?

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int interpolationSearch(int sortedArray[], int toFind, int len) {
    // Returns index of toFind in sortedArray, or -1 if not found
    int low = 0;
    int high = len - 1;
    int mid;

    while (sortedArray[low] <= toFind && sortedArray[high] >= toFind) {
        mid = low + ((toFind - sortedArray[low]) * (high - low)) /
              (sortedArray[high] - sortedArray[low]);

        if (sortedArray[mid] < toFind) {
            low = mid + 1;
        } else if (sortedArray[mid] > toFind) {
            high = mid - 1;
        } else {
            return mid;
        }
    }

    if (sortedArray[low] == toFind)
        return low;
    else
        return -1; // Not found
}

int main(void) {
    srand(time(0));
    int arr[100000];
    for (int i=0; i<100000; i++) {
        arr[i] = rand()%100000;
    }

    int length = sizeof(arr)/sizeof(int);
    qsort(arr,length,sizeof(int),order);

    for (int j=0; j<10000; j++) {
        interpolationSearch(arr,rand()%100000,length);
    }
}

阅读 289

收藏
2020-07-28

共1个答案

小编典典

子表达式: ((toFind - sortedArray[low]) * (high - low))

…可以很容易地评估为: ((99999-0) * (99999-0)) == 99999^2

…比2 ^ 31(== 32位有符号整数的范围)大得多。

一旦超过2 ^ 31-1,整数将溢出为负数,因此为负索引。如果它超过2 ^
32(它也可以这样做),那么(很可能在技术上是未定义的)您将丢失高阶位,并且最终将得到有效的随机偏移,包括正负值。

为避免所有这些情况,您需要仔细进行数学运算,以确保所有子表达式都不会产生整数溢出。通常,最简单的方法是将其转换为浮点数,其范围比32位整数大许多数量级。

在最终分析中,像这样的用于二进制搜索的插值通常是不值得的-计算插值的开销通常大于它“保存”的循环的几次额外迭代。

2020-07-28