将字符串插入C ++ Stl集的时间复杂度

时间:2019-01-26 19:25:47

标签: c++ string stl set time-complexity

插入字符串以设置c ++ STL容器的时间复杂度是多少? 据我说,它应该是O(xlogn),其中x是要插入的字符串的长度,n是set的大小。同样,要设置的字符串复制在字符串长度上应该是线性的。 但是我的这段代码可以立即运行。

#include<bits/stdc++.h>
using namespace std;
int main(){

    set<string> c;
    string s(100000,'a');
    for(int i=0;i<100000;i++){
        c.insert(s);
    }

}   

我在哪里错了,难道难道不是10 ^ 10的数量级吗?

2 个答案:

答案 0 :(得分:0)

将单个元素插入std::set的复杂度为O(log n),因为它是基于红黑树(https://en.wikipedia.org/wiki/Red%E2%80%93black_tree)。

所以是的,您可以假设它花费O(x * log n),其中x是字符串的长度。

当您尝试插入n个不同的元素时,算法的复杂度将为O(n * log n)

您的情况:

您试图一次又一次地插入相同的字符串,但是std::set只能包含唯一的元素,因此在您的示例中,您的集合将仅包含1个字符串。

这种方式在每次迭代中(当然,在第一次迭代之后)std::set仅进行一次比较,并决定不放置相同的字符串。

这就是为什么您的代码运行如此之快的原因。


PS在这种情况下,编译器也可以进行一些优化。

答案 1 :(得分:0)

您应该以某种方式使用 set,以减少优化循环的风险,例如通过添加return c.size();

此外,您对迭代次数的选择可能太低。在循环计数器中添加一个数字,您将看到明显的运行时间。

现代CPU可以轻松处理> 2 * 10 9 ops / s。假设您的编译器使用memcmp,它可能是手工矢量化的,并且具有一个很小的工作集(例如您的工作集),则您完全是从缓存中进行工作的,并且每次比较(使用AVX2)最多可以达到512字节的吞吐量。假设每次迭代的速率为10个周期,我们仍然可以比较> 10 10 字节/秒。因此,您的程序应在<1 s的中等硬件上运行。

请尝试使用此更新的代码:

#include <string>
#include <set>
using namespace std;
int main(){

    set<string> c;
    string s(100000,'a');
    for(int i=0;i<1000000;i++) { // Add a digit here
        c.insert(s);
    }
    return c.size(); // use something from the set
}

在(-O3)上启用优化后,这需要大约5秒钟才能在我的系统上运行。

换句话说,是的,插入二叉树的复杂度为O(log n),但是比较字符串的复杂度为O(n)。这些n不相同,在map的情况下,它表示映射的大小;在string的情况下,n表示字符串的长度。

在您的特定情况下,地图只有一个元素,因此插入值为O(1)。您纯粹从字符串比较中获得线性复杂度O(n),其中 n string_length * number_of_iterations