|
#include <cassert> |
|
#include "search.h" |
|
|
|
// Value |
|
// ^ |
|
// | |
|
// max +-----------------* |
|
// | /| |
|
// | / | |
|
// | / | |
|
// | / | |
|
// | / | |
|
// | / | |
|
// key +----------* | |
|
// | /| | |
|
// | / | | |
|
// | / | | |
|
// | / | | |
|
// | / | | |
|
// | / | | |
|
// min +---* | | |
|
// | | | | |
|
// | | | | |
|
// | | | | |
|
// | | | | |
|
// +---+------+------+---> Index |
|
// I_min I_key I_max |
|
// |
|
// (I_key - I_min) / (key - min) = (I_max - I_min) / (max - min) |
|
// I_key = I_min + (key - min) * (I_max - I_min) / (max - min) |
|
// |
|
// The interpolation search is similar to binary search. |
|
// The difference is that the 'middle' is replaced by the 'I_key' above. |
|
// Also, we need to make sure: min <= value at I_key <= max |
|
// If the condition doesn't meet, than we break the loop. |
|
// Otherwise, the process may repeat forever. |
|
// Let's see an example below: |
|
// |
|
// Index 0 1 2 3 4 5 |
|
// Data -10 4 10 30 32 40 |
|
// |
|
// Example: Search key 25 |
|
// 1) L: 0, R: 5 -> m: Data[L] = -10, M: Data[R] = 40 |
|
// |
|
// idx = Floor( L + (key - m) * (R - L) / (M - m) ) |
|
// = Floor( 0 + 35 * 5 / 50 ) = Floor( 3.5 ) = 3 |
|
// |
|
// Data[idx] = 30 > key = 25 => R = idx - 1 = 2 |
|
// |
|
// Now, the key = 25 is already larger than Data[R] = 20. |
|
// We should stop processing here. |
|
// Otherwise, the process will repeat forever. |
|
// |
|
// |
|
// 2) L: 0, R: 2 -> m: Data[L] = -10, M: Data[R] = 10 |
|
// |
|
// idx = Floor( L + (key - m) * (R - L) / (M - m) ) |
|
// = Floor( 0 + 35 * 2 / 20 ) = Floor( 3.5 ) = 3 |
|
// |
|
// Data[idx] = 30 > key = 25 => R = idx - 1 = 2 |
|
// |
|
// 3) L: 0, R: 2 -> m: Data[L] = -10, M: Data[R] = 10 |
|
// |
|
// Repeat 2's process ..... |
|
// |
|
int recursiveInterpolationSearch(int list[], int left, int right, int key) |
|
{ |
|
int min = list[left]; |
|
int max = list[right]; |
|
|
|
if (left > right || key < min || key > max) { |
|
return NOT_FOUND; |
|
} |
|
|
|
int middle = left + (key - min) * (right - left) / (max - min); |
|
|
|
if (key == list[middle]) { |
|
return middle; |
|
} else if (list[middle] > key) { |
|
right = middle - 1; |
|
} else { // list[middle] < key |
|
left = middle + 1; |
|
} |
|
return recursiveInterpolationSearch(list, left, right, key); |
|
} |
|
|
|
int iterativeInterpolationSearch(int list[], int left, int right, int key) |
|
{ |
|
int middle; |
|
int min = list[left], max = list[right]; |
|
// Make sure min <= key <= max, or middle will be < left or > right |
|
while(left <= right && key >= min && key <= max) { |
|
min = list[left]; |
|
max = list[right]; |
|
middle = left + (key - min) * ((right - left) / (max - min)); |
|
|
|
if (key == list[middle]) { |
|
return middle; |
|
} else if (list[middle] > key) { |
|
right = middle - 1; |
|
} else { // list[middle] < key |
|
left = middle + 1; |
|
} |
|
} |
|
|
|
return NOT_FOUND; |
|
} |
|
|
|
int interpolationSearch(int list[], const unsigned int length, int key) |
|
{ |
|
assert(list && length); |
|
// return recursiveInterpolationSearch(list, 0, length - 1, key); |
|
return iterativeInterpolationSearch(list, 0, length - 1, key); |
|
} |