【问题标题】:Binary search runs as slow as linear one, plus finding first value二进制搜索运行速度与线性搜索一样慢,而且要找到第一个值
【发布时间】:2016-07-21 11:48:10
【问题描述】:

我正在尝试实现一个密度图,该图由 n x m 维的 2D 数组表示,其中每个单元格的值介于 0 和 1 之间,表示随机找到该单元格的概率。例如:

0.04   0.06   0.10
0.50   0.01   0.05
0.09   0.10   0.05

我们有 50% 的机会找到坐标 (1,0),4% 的机会找到坐标 (0,0) 等等。

为了找到这个单元格,我使用了累积和。上面的数组将被表示为:

0.04   0.69   0.90
0.54   0.70   0.95
0.63   0.80   1.00

由于我在 C++ 中工作,因此我使用的是大小为 (n * m) 的一维数组,则上面的内容由:

0.04   0.54   0.63   0.69   0.70   0.80   0.90   0.95   1.00

要在这个概率内找到一个随机单元格,我可以使用这种线性方法:

while (internal[i] < k) {
    if (internal[i] >= k) break;
    i++;
}

其中k是0到1之间的随机数

然而,这很慢,因为我的数组用于表示图像(因此它可能变得非常大),而且我不得不多次调用这个函数。

为了加快程序速度,我尝试在我的数组中实现二进制搜索。这个实现如下:

int DensityMap::simple_binary_search(double value, int first, int last) {

int index = -1;
int mid_point;

while (first <= last) {
    mid_point = first + (last - first) / 2;

    if (value >= internal[mid_point] && value < internal[mid_point + 1]) {
        index = mid_point;
        break;
    } else if (value < internal[mid_point]) {
        last = mid_point - 1;
    } else {
        first = mid_point + 1;
    }

}

return index;

}

返回的索引是正确的(与线性搜索相同),但速度增益相当糟糕,我不明白为什么。例如,对于 10 000 x 10 000 随机填充的密度图,二分搜索需要 3.172 秒,线性搜索需要 3.288 秒。

二进制搜索的另一个问题是,有时结果可能会有所不同。考虑以下示例:

Probability array -> 0.50   0.00   0.40   0.00   0.00   0.00   0.05   0.00   0.05
Cumulative sum    -> 0.50   0.50   0.90   0.90   0.90   0.90   0.95   0.95   1.00

在这种情况下,如果我的随机数是 0.90,线性搜索将在该数字第一次出现时停止(索引 2),而二进制搜索将查看中间索引,该值也是 0.90,所以它将返回(索引 4)作为结果,这不是我想要的 ..

还有其他方法可以加快搜索速度并保持我想要的结果吗? (意思是找到一个值的第一次出现)。我想一旦我找到二进制搜索的结果,我可以反向迭代,但我担心它会进一步减慢程序,这将是非常可怕的

谢谢

【问题讨论】:

  • 你的算法看起来不错。您是否检查过 while 循环了多少个循环?你是只测量搜索时间,还是整个程序运行?
  • @erip std::binary_search 只返回布尔值,即测试是否存在。
  • @user2672165 哎呀。 :)
  • 我只测量了每种方法的时间,但我没有检查while的通道数。感谢您的帮助

标签: c++ algorithm search


【解决方案1】:

使用 std::lower_bound 返回大于或等于输入的第一个元素(即正是您需要的),或者如果您想自己实现它,请检查它的实现。找到元素后停止的问题,您应该将相等的元素视为更大。

【讨论】:

  • 感谢您的帮助,这正是我所需要的!
  • @B.Kovac 出于好奇,它的比较如何?
  • 它相当可比,这很奇怪,因为根据文档,复杂性应该是对数的,但它可能会通过随机访问迭代器得到改进,我现在正在研究它
  • 如果你的迭代器不是 RandomAccessIterator,那么它在线性时间内工作(但在比较的对数中)
【解决方案2】:

如果您使用的是 c++,则可以使用 std::upper_bound 方法,该方法将准确返回您愿意获得的值(第一次出现的值大于给定数字的索引)

【讨论】:

    猜你喜欢
    • 2010-12-23
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 2012-05-18
    • 2019-12-20
    相关资源
    最近更新 更多