线性搜索与二进制搜索效率

时间:2019-08-13 17:40:23

标签: c++ algorithm performance search binary-search

我目前正在研究不同的搜索算法,并且做了一些程序来看看效率上的差异。二进制搜索应该比线性搜索更快,但是时间的确显示了其他情况。我在代码中犯了错误还是这是一种特殊情况?

#include <chrono>
#include <unistd.h>

using namespace std;

const int n=1001;
int a[n];

void assign() {
    for (int i=0; i<n; i++) {
        a[i]=i;
    }
}

void print() {
    for (int i=0; i<n; i++) {
        cout << a[i] << endl;
    }
}

bool find1 (int x) {
    for (int i=0; i<n; i++) {
        if (x==a[i]){
            return true;
        } 
    } return false;
}

bool binsearch(int x) {
    int l=0,m; 
    int r=n-1;
    while (l<=r) {
        m = ((l+r)/2);
        if (a[m]==x) return true;
        if (a[m]<x) l=m+1;
        if (a[m]>x) r=m-1;

    }
    return false;
}

int main() {

    assign();
    //print();
    auto start1 = chrono::steady_clock::now();
    cout << binsearch(500) << endl;
    auto end1 = chrono::steady_clock::now();

    auto start2 = chrono::steady_clock::now();
    cout << find1(500) << endl;
    auto end2 = chrono::steady_clock::now();
    cout << "binsearch: " << chrono::duration_cast<chrono::nanoseconds>(end1 - start1).count()
        << " ns " << endl;
    cout << "linsearch: " << chrono::duration_cast<chrono::nanoseconds>(end2 - start2).count()
        << " ns " << endl;

    return 0;
}

3 个答案:

答案 0 :(得分:8)

您的测试数据集太小(1001个整数)。填充后,它将完全适合最快的(L1)缓存;因此,您受分支复杂性的约束,而不是内存的约束。 与简单的线性遍历相比,二进制搜索版本显示出更多的分支错误预测,导致更多的管道停顿。

我将n增加到1000001,还增加了测试通过次数:

auto start1 = chrono::steady_clock::now();
for (int i = 0; i < n; i += n/13) {
    if (!binsearch(i%n)) {
        std::cerr << i << std::endl;
    }
}
auto end1 = chrono::steady_clock::now();

auto start2 = chrono::steady_clock::now();
for (int i = 0; i < n; i += n / 13) {
    if (!find1(i%n)) {
        std::cerr << i << std::endl;
    }
}
auto end2 = chrono::steady_clock::now();

我得到了不同的结果:

binsearch: 10300 ns
linsearch: 3129600 ns

还请注意,您不应该在定时循环中调用cout,但是您确实需要使用find的结果,以免对其进行优化。

答案 1 :(得分:7)

我认为N = 1001足以说明二进制搜索具有更好的性能。 Specific realizations of linear search仅对于较小的N(大约<100)可能会更快。但是,在您的情况下,如此奇怪的结果的原因是轮廓分析测量不正确。在第一种算法(二进制搜索)的计算过程中,您的所有数据均已成功缓存,从而大大提高了第二种算法(线性搜索)的性能。

如果只交换他们的电话,您将得到相反的结果:

binsearch: 6019 ns 
linsearch: 77587 ns 

对于精确的测量,您应该使用特殊的框架(例如google benchmark),以确保两种算法的“公平条件”。

其他在线benchmarking tool(它在许多负载未知的AWS机器的池上运行测试代码,并返回平均结果)为您的代码提供了这些图表,而没有更改(也具有相同的n = 1001) :

enter image description here

答案 2 :(得分:0)

充分利用两者!

进行某种程度的二进制搜索,然后切换到线性搜索。这样想,二进制搜索有很多簿记;线性搜索更快,因为它“更简单”。

当我第一次使用汇编语言(在1970年代)对它进行试验时,我推断对二进制进行搜索可以减少到大约4个项目,然后对线性进行搜索是最佳的。但是YMMV;这取决于硬件,比较两个项目(浮点数/整数/字符串/任何东西)的复杂性等。

提示:计算代码中的操作数。我发现binsearch()例程中每个步骤所需的操作大约是线性扫描的两倍。