前面介绍的二分查找,其复杂度为O(logn),在数据量较多的情况下比顺序查找效率高很多:
机器学习入坑者:二分查找原理及python与C++实现详解zhuanlan.zhihu.com当然,二分查找要求数据必须是有序的,这也规定了其适用范围。在二分查找的基础上进一步的约束数据,要求数据是有序且数值分布均匀的,可以获得更加高效的“插值查找”算法。我们首先回顾一下二分查找的流程:
上图中蓝色圈为左边界left,粉色圈为右边界right,绿色圈为middle(简写为mid)位置,我们知道,中间位置的计算方式如下:
可以对其进行变形如下:
上面的1/2代表区间长度每次缩减一半,也就是控制区间缩减幅度的因子。二分查找并没有考虑数据中数值的情况,仅仅使用了数值是有序的这一信息。
现在,来看下述的数值有序且分布均匀数据:
data
如果搜索的目标是2,那么区间长度每次都缩减为一半合理吗?显然是不合理的,因为2这个值比较小,明显比较偏向于数据的起始位置;如果搜索的目标是25,区间减半的方式同样不合理。
所以,可以改变二分查找的区间缩减策略,根据搜索的值来确定区间缩减幅度,使其不再是固定的1/2,这种想法就是“插值查找”,其中间位置计算方式如下:
如果alpha用于衡量搜索目标值距离左边界的远近,就可以使用下述公式进行表达,其中tar表示目标值,D表述有序数值:
此时,如果目标值tar和左边界值D[left]差的多,则中间位置mid更靠右;如果目标值tar和左边界值差的少,则中间位置mid更靠左。也就是说,插值查找算法的中间位置mid不是真的在中间了,而是根据目标值和边界值的关系动态的确定。
插值查找算法和二分查找算法的区别主要就在于中间位置mid的确定,它们在终止条件和判断条件上都是相同,在此不做重复。
1、插值查找性能分析
插值查找的时间复杂度为O(loglogn),最坏情况为O(n)。具体计算可以参考论文[1, 3],其中包含下载地址。
2、python实现
def
3、C++实现
int
参考:
【1】Andersson A, Mattsson C. Dynamic Interpolation Search in o (log log n) Time[C]//International Colloquium on Automata, Languages, and Programming. Springer, Berlin, Heidelberg, 1993: 15-27.
【2】https://blog.csdn.net/qq_29542611/article/details/79392661
【3】http://www.cs.technion.ac.il/~itai/publications/Algorithms/p550-perl.pdf