Участник:Shovkoplyas Grigory — различия между версиями
| Строка 8: | Строка 8: | ||
=== Псевдокод === | === Псевдокод === | ||
<code style = "display: inline-block;"> | <code style = "display: inline-block;"> | ||
| − | + | function interpolation_search(x) | |
| − | l = 0 | + | l = 0 // левая граница поиска (будем считать, что элементы массива нумеруются с нуля) |
| − | r = n - 1 | + | r = n - 1 // правая граница поиска |
| − | while a[l] | + | while a[l] \le x and x \le a[r] |
m = l + (x - a[l]) / (a[r] - a[l]) * (r - l); // элемент, с которым будем проводить сравнение | m = l + (x - a[l]) / (a[r] - a[l]) * (r - l); // элемент, с которым будем проводить сравнение | ||
if a[m] == x | if a[m] == x | ||
| − | result = m | + | result = m |
if a[m] < x | if a[m] < x | ||
| − | l = m + 1 | + | l = m + 1 |
else | else | ||
| − | r = m - 1 | + | r = m - 1 |
if a[l] == x | if a[l] == x | ||
| − | result = l | + | result = l |
else | else | ||
| − | result = -1 | + | result = -1 // если такого элемента в массиве нет |
</code> | </code> | ||
Версия 13:15, 15 июня 2014
Содержание
Идея
Рассмотрим задачу: найти слово в словаре. Если оно начинается на букву "А", то никто не будет искать его в середине, а откроет словарь ближе к началу. В чём разница между алгоритмом человека и другими? Отличие заключается в том, что алгоритмы вроде двоичного поиска не делают различий между "немного больше" и "существенно больше".
Алгоритм
Пусть — отсортированный массив чисел из чисел, — значение, которое нужно найти. Поиск происходит подобно двоичному поиску, но вместо деления области поиска на две примерно равные части, интерполирующий поиск производит оценку новой области поиска по расстоянию между ключом и текущим значением элемента. Если известно, что лежит между и , то следующая проверка выполняется примерно на расстоянии от .
Псевдокод
function interpolation_search(x)
l = 0 // левая граница поиска (будем считать, что элементы массива нумеруются с нуля)
r = n - 1 // правая граница поиска
while a[l] \le x and x \le a[r]
m = l + (x - a[l]) / (a[r] - a[l]) * (r - l); // элемент, с которым будем проводить сравнение
if a[m] == x
result = m
if a[m] < x
l = m + 1
else
r = m - 1
if a[l] == x
result = l
else
result = -1 // если такого элемента в массиве нет
Время работы
Асимптотически интерполяционный поиск превосходит по своим характеристикам бинарный. Если ключи распределены случайным образом, то за один шаг алгоритм уменьшает количество проверяемых элементов с до . То есть, после -ого шага количество проверяемых элементов уменьшается до . Значит, остаётся проверить только 2 элемента (и закончить на этом поиск), когда . Из этого вытекает, что количество шагов, а значит, и время работы составляет .
При "плохих" исходных данных (например, при экспоненциальном возрастании элементов) время работы может ухудшиться до .
Эксперименты показали, что интерполяционный поиск не настолько снижает количество выполняемых сравнений, чтобы компенсировать требуемое для дополнительных вычислений время (пока таблица не очень велика). Кроме того, типичные таблицы недостаточно случайны, да и разница между значениями и становится значительной только при очень больших . На практике при поиске в больших файлах оказывается выгодным на ранних стадиях применять интерполяционный поиск, а затем, когда диапазон существенно уменьшится, переходить к двоичному.
Литература
Д.Э. Кнут: Искусство программирования (том 3)
Wikipedia: Interpolation search
Wikipedia: Интерполирующий поиск
