Проблема в выражении, которое вычисляет mid
. Продукт может легко переполниться даже с 32-битными целыми числами. Тогда это становится отрицательным. Вероятно, было бы лучше выполнить разделение перед продуктом.
Изменение средних вычислений для использования 64-битных целых чисел (по крайней мере, для промежуточных вычислений) исправляет проблемы.
Ниже моя модифицированная версия (int64_t определено в <stdint.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;
int l = sortedArray[low];
int h = sortedArray[high];
while (l <= toFind && h >= toFind) {
int64_t high_low = (high - low);
int64_t toFind_l = (toFind - l);
int64_t product = high_low*toFind_l;
int64_t h_l = h-l;
int64_t step = product / h_l;
mid = low + step;
/* mid = (low + high)/2;*/
int m = sortedArray[mid];
if (m < toFind) {
l = sortedArray[low = mid + 1];
} else if (m > toFind) {
h = sortedArray[high = mid - 1];
} else {
return mid;
}
}
if (sortedArray[low] == toFind)
return low;
else
return -1; // Not found
}
Еще более простым решением было бы сделать дихотомический поиск вместо интерполяции, просто используя: mid = (low + high) / 2
. даже если он сходится немного медленнее, чем интерполяция, он избегает нескольких операций, включая произведение и деление, тем самым делая внутренний цикл быстрее. Не уверен, что потенциальная более быстрая сходимость интерполяции компенсирует эту потерю простоты.
Я провел несколько тестов производительности. Источник моей тестовой программы включен в этот вопрос
Удивительно (для меня) использование float дает более эффективную программу, чем использование больших целых чисел. В моей системе бинарный поиск стал быстрее примерно для 1000 элементов в массиве. Для массивов размером 100000 интерполяционный поиск почти в два раза быстрее, чем простой двоичный поиск.