【问题标题】:Binary search with hint带提示的二分查找
【发布时间】:2014-12-24 03:21:14
【问题描述】:

我有一个简单的std::vector,其中包含一些数字,这些数字是按升序排列的。我想查找一个元素,到目前为止我使用的是:

return std::lower_bound(vec.begin(), vec.end(), needle);

needle 是我要查找的元素。但是,我的向量往往很长(数百万个元素),但大多数时候内容是相对可预测的,如果第一个元素为零,最后一个元素是N,那么两者之间的元素有值接近(N * index) / vec.size(),因此是可预测的。

是否有修改下限,接受提示(类似于std::map::emplace_hint() 所做的),例如:

assert(!vec.empty());
std::vector<int>::iterator hint = vec.begin() + std::min(vec.size() - 1,
    (needle * vec.size()) / vec.back());
if(*hint > needle)
    return std::lower_bound(vec.begin(), hint, needle);
else
    return std::lower_bound(hint, vec.end(), needle);

这会起作用,但是lower_bound 忽略了它已经接近解决方案,并且很可能会开始将间隔分成两半(看看我们知道针最有可能不是的地方),采取不必要的许多步骤。我知道有一种算法从第 1 步开始,它会翻倍,直到超过指针,然后在给定的时间间隔内进行二进制搜索。

我忘记了算法的名称是什么。是否在 STL 中实现?

【问题讨论】:

  • @ChrisWard1000 向量会有更好的缓存性能。
  • @ChrisWard1000 原因可能是您想要便宜的插件。
  • @ChrisWard1000 因为插入到set 是摊销的,并且前面的算法会生成已经排序的元素,所以对于插入vector 来说,IMO 的成本要低得多。
  • @ChrisWard1000 为什么你认为std::set 使用比std::lower_bound 更好的算法?它们都是 O(log n),vector 通常具有更好的性能。
  • 我认为算法的名称是"one-sided binary search"。它不在标准 C++ 库中。

标签: c++ algorithm search


【解决方案1】:

我认为您正在寻找的算法称为interpolation search,它是二进制搜索的一种变体,它不是查看数组的中点,而是在数组端点之间线性插值以猜测密钥应该在哪里。对于按照您的方式构建的数据,预期的运行时间是 O(log log n),比标准的二分搜索快得多。

这个算法在 C++ 中没有标准实现,但是(作为一个完全无耻的插件)我碰巧用 C++ 编写了这个算法。 My implementation is available online 如果您有兴趣了解它的工作原理。

希望这会有所帮助!

【讨论】:

  • 我明白了。这不是我的意思,我以前不知道(很好的答案!)。我只想使用插值搜索的一步,然后继续使用我忘记名称的某种二进制文件。如果数组不是“线性插值”(最坏的情况是什么),该算法的行为如何?此外,我可以看到为什么这不在 STL 中,因为该算法只能处理数字,因此很难(如果不是不可能的话)使其与定义了比较的泛型类型(例如字符串)一起使用。我说的对吗?
  • @theswine 在最坏的情况下,该算法的运行时间为 O(n)。只有当数据呈指数增长时才会发生这种情况,而这在实践中根本不可能发生。我认为你是对的,因为它被遗漏的原因是很难使用非数字类型进行这项工作,尽管你可以想象需要某种客户端指定的插值函数作为最终参数。
  • @theswine 不用担心!如果你发现了一个错误,我肯定会想知道它。把它放在 GPU 上真是太酷了!
猜你喜欢
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 2015-12-10
  • 1970-01-01
  • 2021-03-07
  • 2018-03-27
  • 2012-12-24
相关资源
最近更新 更多