为什么我得到基于RB-tree的C++ std :: set的插入时间基准的常量而不是对数曲线?

Cir*_*四事件 11 c++ stl

我正在将BST与Heap进行比较:Heap vs Binary Search Tree(BST),但当我尝试对两者进行基准测试并比较结果时,我无法解释BST的数据.

首先,我确认标准库确实使用了红黑树:C++中STL集的底层数据结构是什么?

然后我跑了这个基准.

main.cpp中

#include <chrono>
#include <iostream>
#include <random>
#include <set>

int main(int argc, char **argv) {
    size_t i, n;
    std::set<int> bst;
    std::random_device dev;
    unsigned int seed = dev();
    std::mt19937 prng(seed);
    std::uniform_int_distribution<> dist;

    if (argc > 1) {
        n = std::stoi(argv[1]);
    } else {
        n = 1000000;
    }
    for (i = 0; i < n; ++i) {
        auto random_value = dist(prng);
        auto start = std::chrono::steady_clock::now();
        bst.insert(random_value);
        auto end = std::chrono::steady_clock::now();
        auto dt_bst = end - start;
        std::cout << random_value << " "
            << std::chrono::duration_cast<std::chrono::nanoseconds>(dt_bst).count() << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

plot.gnuplot:

#!/usr/bin/env gnuplot
set terminal png size 1024, 1024
set output "bst_vs_heap.png"
set title "BST insert time"
set xlabel "size"
set ylabel "nanoseconds"
plot "main.dat" using 2 notitle
Run Code Online (Sandbox Code Playgroud)

编译,运行和绘图:

g++ -ggdb3 -O3 -std=c++17 -Wall -Wextra -pedantic-errors -o main.out main.cpp
./main.out 10000000 > main.dat
./plot.gnuplot
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述

为什么我没有像理论数据结构那样看到一个很好的对数曲线,而是一些带有一些异常值的恒定线?

Ubuntu 18.04,GCC 7.3,Intel i7-7820HQ CPU,DDR4 2400 MHz RAM,联想Thinkpad P51.

Cir*_*四事件 10

时间可能不像评论中提到的那么准确,所以我试图将一堆插入组合在一起并计时它们以改善信噪比,并且它有效,我现在可以看到一个对数:

#include <chrono>
#include <iostream>
#include <random>
#include <set>

int main(int argc, char **argv) {
    size_t i, j, n, granule;
    std::set<int> bst;
    std::random_device dev;
    unsigned int seed = dev();
    std::mt19937 prng(seed);
    std::uniform_int_distribution<> dist;
    int *randoms;

    if (argc > 1) {
        n = std::stoi(argv[1]);
    } else {
        n = 1000000;
    }
    if (argc > 2) {
        granule = std::stoi(argv[2]);
    } else {
        granule = 10;
    }
    randoms = new int[granule];
    for (i = 0; i < n / granule; ++i) {
        for (j = 0; j < granule; ++j) {
            randoms[j] = dist(prng);
        }
        auto start = std::chrono::high_resolution_clock::now();
        for (j = 0; j < granule; ++j) {
            bst.insert(randoms[j]);
        }
        auto end = std::chrono::high_resolution_clock::now();
        auto dt_bst = end - start;
        std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(dt_bst).count() << std::endl;
    }
    delete[] randoms;
}
Run Code Online (Sandbox Code Playgroud)

命令:

./main.out 100000000 10000
Run Code Online (Sandbox Code Playgroud)

图形:

在此输入图像描述

  • 这或多或少是理论所期望的.通过在向量中收集时序,而不是直接将其发送到`std :: cout`,可以进一步平滑它.然后重复实验N次,每次用相同的随机种子开始.总结每个测量点的所有结果.在此过程中,请考虑丢弃每次插入的最小/最大点数(以最大限度地减少噪音).最后,打印矢量中的值除以N(如果消除了异常值,则打印N-2). (3认同)