【问题标题】:Could this recursive binary search algorithm be more efficient?这种递归二分搜索算法会更有效吗?
【发布时间】:2015-10-03 02:54:04
【问题描述】:

我已经看到了这个算法的很多不同的实现,但我想知道除了使搜索二进制之外,是否还有其他方法可以提高效率。我设计了这个特定版本的算法,因此将立即检查数组/列表的边缘和中点是否有正在搜索的键,以避免在您要查找的键只是第一个、中间的键时循环搜索,或最后一个元素。

def searchRB(the_array, the_key, imin, imax):
    print("searching")
    found = False
    if (0 > the_key or the_key > len(the_array)):
        return found
    else:
        imid = imin + ((imax - imin) // 2)
        if imid == the_key or imin == the_key or imax == the_key:
            found = True
            return found
        elif the_array[imid] > the_key:
            return searchRB(the_array, the_key, imin, imid-1)
        elif the_array[imid] < the_key:
            return searchRB(the_array, the_key, imid+1, imax)
        else:
            return found

例如,如果您在 1-100 的列表中查找数字 1,这将在第一个循环中找到它,这与其他一些实现不同。

但是,我不确定这是否真的提高了效率(某些边缘情况除外),并且如果您继续循环检查列表/数组中的第一个、中间和结束值实际上是有害的,并且每次都必须检查这三个值。

这种算法的实现是好是坏,还是我只是扯淡?

【问题讨论】:

  • 迭代二分查找会更高效。
  • 很有趣,您能详细说明一下为什么会这样吗?
  • 如何开始搜索? the_key、imin、imax 的值是多少?
  • the_key = 您要搜索的数字,imin = 您搜索范围内的最小值,imax = 您搜索范围内的最大值。
  • 因为迭代实现避免了更多函数调用的开销,这在 Python 中并不是非常快。我认为这是分裂的头发,是的:渐近(the_array 的大小变大),快速识别端点并没有好处。与元素的数量相比,可能的端点数量非常少,因此您会在平均元素检查上浪费额外的时间来检查罕见情况。此外,found 变量没有用:只需返回 FalseTrueFalse(分别)在您现在返回 found 的位置,并删除两行 found = &lt;bool-const&gt;

标签: python algorithm recursion binary-search


【解决方案1】:

最主要的是从递归方法更改为使用while循环,节省了调用堆栈(因为python没有尾递归)。

您有一些可以优化的小冗余。 算法已经足够优化了,除非你懂编译器,否则不要over optimise

如果你沿着左边的树向下走,你会一遍又一遍地比较相同的 imin,但是这整行可能是并行的或按顺序完成的

if the_array[imid] == the_key or the_array[min] == the_key or the_array[imax] == the_key:

这也可能会影响缓存性能,因为您将始终将 the_array[min] 保存在缓存中。有时,编译器会从数组中存储一个块,围绕您尝试在缓存中访问的索引。 您可能会浪费更多的缓存,而不仅仅是 1 值。

也可以优化这样的语句,您可以只输入 return True ,但这应该由编译器再次选择。

found = True return found

没有found 作为对象会优化代码,因为该对象不会一直存储在内存中。

这个 else 语句似乎是多余的,因为没有办法得到那个 else else return found

实际的相关优化将来自对数据集的更多了解。

如果您能够预处理数据(或拥有有关数据的更多信息),您可以执行其他算法。

【讨论】:

  • 我在这里注意到的一件事是,搜索与键等价的最小值、最大值并不能很好地工作。就像你说的,我这样做的方式只是在每次循环时比较相同的最小值和最大值(这是没用的),但如果你使用the_key == the_array[imin] or the_key == the_array[imax],索引就会超出范围。我认为最好完全放弃它,并将密钥与中点进行比较。
  • 是的,只是比较中点,而且我认为您何时中断的逻辑有点错误,它应该将 mid 与 0 和数组的长度进行比较以确定索引是否在界限内
  • 应该在函数的开头定义imid,并且该语句应该像你说的那样是if 0 &gt; imid or imid &gt; len(the_array):
猜你喜欢
  • 2020-09-06
  • 1970-01-01
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
相关资源
最近更新 更多