同时使用两个中间值(两个指针)进行二进制搜索



我只想把数组分成三个子数组,而不是两个子数组首先,这样做合乎逻辑吗?请帮我理解这个算法并把它写成

def contains(elements, value):
left, right = 0, len(elements) - 1
if left <= right:
middle = (left + right) // 2
if elements[middle] == value:
return True
if elements[middle] < value:
return contains(elements[middle + 1:], value)
elif elements[middle] > value:
return contains(elements[:middle], value)
return False

您确实可以调整二进制搜索,将数组拆分为多个部分,而不仅仅是两个部分。更普遍地说,这是k元搜索背后的想法:

  • 将数组拆分为大小大致相等的k个部分。(对于二进制搜索,这是两半。对于您的搜索,这将是三分之三(

  • 拾取第一个(k-1(节中的最后一个元素用作关键点。(对于二进制搜索,您可以选择前半部分的最后一个元素,即中间元素。对于搜索,这将是阵列中1/3和2/3点的元素。(

  • 根据你的元素与键的比较,(1(停止搜索,因为你找到了你要找的东西,或者(2(递归地探索合适的部分。(在二进制搜索中,你可以向左分支,停止,因为中间的元素是你想要的,或者向右分支。在搜索中,要么(1(发现你的元素是选择要查看的两个元素之一,要么(2(会下降到包含你的元素的第三个元素中。(

至于这是否是个好主意-这很可能是个好想法!在k元搜索中,每次迭代时都会将数组缩小k倍,因此算法的迭代次数大致为logkn=(logn(/(logk(。每一次迭代都着眼于k-1个键,所以您正在做O(k(工作。这意味着所做的功是O((k/log k(n(。当您选择k=e(即约2.7182828(时,数量k/log k最小化,因此选择k=2或k=3是不错的选择。然而,由于处理器缓存的工作方式,我怀疑选择k=2会更快,因为缓存未命中会更少。(嘿!我们在实践中倾向于使用二进制搜索,所以这可能不是一个坏主意。(

有趣的是,数据库中广泛使用的B树数据结构使用类似的东西来存储其元素。由于B-树的结构,B-树通常会选择k作为某个巨大的数字,但在常规数组搜索中,这可能不是一个好主意。

希望这能有所帮助!

最新更新