概念及其介绍:
插值查找算法,其实是对二分查找的改良。同二分查找算法一样,都是针对的是有序数组,换句话说,就是插值查找算法和二分查找算法都是只能在升序或者是降序的数组中查找目标元素。但是插值查找算法作为二分查找算法的“改良版”,它所针对的有序数组又存在另一条限制,就是该数组中的元素必须是均匀分布的,例如:{1,2,3,4,5,6,7,8,9,10}这样的升序数组元素分布就是均匀的,因为元素之间的差值都是同一个值。像{10,30,70,100,500}这样的升序数组元素的分布就不是均匀的
但是插值查找与二分查找算法都各自有优点,当数组中的元素分布是均匀的话,那么插值查找算法的查找效率要高于二分查找算法,但是当数组中的元素分布不是均匀的话,那么二分查找算法的查找效率要高于插值查找算法。
算法思想:
学会了二分查找算法的话,那么插值查找算法就会简单很多,因为插值查找算法就是按照二分查找算法进行改良的,只是有一点不同。
插值查找算法的解题思路和二分查找算法几乎相同,唯一的区别在于,每次与目标元素做比较的元素并非搜索区域内的中间元素,此元素的位置需要通过如下公式计算得出:
Mid = Begin + ( (End - Begin) / (A[End] - A[Begin]) ) * (X - A[Begin])
式子中,各部分的含义分别是:
- Mid:计算得出的元素的位置;
- End:搜索区域内最后一个元素所在的位置;
- Begin:搜索区域内第一个元素所在的位置;
- X:要查找的目标元素;
- A[]:表示整个待搜索序列。
为了方便讲解,我们仍将 Mid 位置上的元素称为 "中间元素"。
使用插值查找算法在 {1,2,3,4,5,6,7,8,9,10} 升序序列中查找元素 2,查找过程如下:
1) 假设序列中各个元素的位置为 0~9,搜索区域为整个序列,通过公式计算出 "中间元素" 的位置:
Mid = 0 + ( (9-0)/(10-1) ) * (2-1) = 1
"中间元素" 的位置为 1,也就是元素 2,显然这是我们要找的目标元素,查找结束。整个查找过程如下所示:
代码展示:
#define LENGTH 10
int interplotion_search(int* nums, int p, int q, int num)
{
int left = p;
int right = q;
//[left,right]之间不存在元素
if (left > right)
{
return -1;
}
//如果数组中只有一个元素,那么判断是否是所查找的元素
if (left == right)
{
if (num == nums[left])
{
return left;
}
else
return -1;
}
//找到进行比较元素的位置
int mid = left + ((right - left) / (nums[right] - nums[left]))*(num - nums[left]);
//设置函数递归的出口
if (num == nums[mid])
{
return mid;
}
if (num > nums[mid])
{
left = mid + 1;
interplotion_search(nums, left, right, num);
}
else
{
right = mid - 1;
interplotion_search(nums, left, right, num);
}
}
int main()
{
int nums[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
int ret = interplotion_search(nums, 0, LENGTH - 1, 16);
if (ret != -1)
{
printf("find it,下标是:%d\n", ret);
}
else
{
printf("can't find it\n");
}
return 0;
}