哪种方法是更快的矢量(插入然后排序)或设置?

时间:2014-07-26 06:33:12

标签: c++ performance stl

我有一系列数字(未分类,没有重复)与目标进行排序。

方法1:插入向量。 O(n),使用排序算法和排序。 O(nlogn)

方法2:插入集合。 O(nlogn)

哪种方法会更快?

我觉得set会更快,因为vector中的每个插入都必须分配 完成数组元素并复制它然后删除它可能是昂贵的。但是我在网上阅读了大部分地方的矢量已经过了。

任何人都可以建议我使用正确的逻辑哪一个更快?

编辑: 如果我们事先不知道哪个元素会更快设置或向量 (对于两个元素都没有,并且元素的数量很大? 注意:如果没有元素是大的设置似乎是更好的选择,但它对小也有好处吗?不知道)

3 个答案:

答案 0 :(得分:4)

  • 如果您事先了解了许多要素,您可以reserve()向量中的空格以避免重新分配,使第一选择非常有趣(快速插入,单一的)。

    如果您需要执行一次,请转到std::vector<>。如果稍后在程序中发生其他插入,则std::set<>可能会更有趣。

  • 如果您事先不知道预期的尺寸,则可能会对矢量进行重新分配,std::set<>是一个不错的选择(更好的理论平均复杂度) )。

      

    O(n)+ O(n * log(n))对于 vs O(n * log(n))的集合

  • 如果元素的数量非常少,您仍然可以预留一些空间(例如,如果您需要10个元素,则可以保留100个为安全),并使用std::vector

无论如何,分析这两种解决方案总是一种很好的做法,实际结果将取决于输入的初始排序状态(以及其他内容),以及每个容器的实施质量。

注意:

  • 请记住,std::set有一个更大的记忆足迹,如果它对你很重要。

答案 1 :(得分:1)

这取决于您的使用案例。

设置

  

+快速数据插入O(logn)

     

+您无需关心排序

     

- 由于 set 是作为树实现的,因此每个元素都有内存开销。

     

-Data可以分布在内存堆中,因此CPU缓存效果不佳。

vector

  

+数据包含在连续的内存块中。所以,你的CPU缓存更好。

     

+您的搜索相同O(logn)

     

+你可以reserve内存。

     

- 你需要在每次改变后进行排序。

所以,如果你有很多元素并且做了一次插入,很多搜索&#34;,我更喜欢 vector 。如果您进行了许多插入/搜索查询,最好坚持使用设置

用O()术语思考我说向量插入成本是O(nlogn),但是在所有插入之后可以调用一次。 设置插入成本为O(logn)并调用每个插入。因此,如果您需要在向量排序后进行插入,您将为向量支付num_insertions*O(nlogn),为设置支付O(log (n+num_insertions)),这实际上更便宜。< / p>

答案 2 :(得分:1)

我以为我会使用分析器来研究这个问题。我的代码:

//g++ -std=c++11 -Wall vectorvsset.cpp -g -pg -o vectorvsset
#include <time.h>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

void GenRandom(vector<int32_t> &original)
{
    original.clear();
    for(size_t i=0; i<10000; i++)
        original.push_back(rand());
}

void TestSet(const vector<int32_t> &original)
{
    set<int32_t> testset;
    testset.insert(original.begin(), original.end());
}

void TestVector(const vector<int32_t> &original)
{
    vector<int32_t> testvec;
    testvec.insert(testvec.end(), original.begin(), original.end());
    sort(testvec.begin(), testvec.end());
}

void TestVectorConvertToSet(const vector<int32_t> &original)
{
    vector<int32_t> testvec;
    testvec.insert(testvec.end(), original.begin(), original.end());
    sort(testvec.begin(), testvec.end());
    std::set<int32_t> testsec(testvec.begin(), testvec.end());
}

int main()
{
    srand(time(NULL));
    cout << "RAND_MAX " <<  RAND_MAX << endl;
    vector<int32_t> original;

    for(size_t i=0; i<100; i++)
    {
        GenRandom(original);

        TestSet(original);

        TestVector(original);

        TestVectorConvertToSet(original);
    }

    return 0;
}

在g ++上使用gprof(Ubuntu 5.4.0-6ubuntu1~16.04.4)5.4.0 20160609我的(缩写)结果是:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
  0.00      1.42     0.00      100     0.00     3.36  TestVector(std::vector<int, std::allocator<int> > const&)
  0.00      1.42     0.00      100     0.00     6.86  TestVectorConvertToSet(std::vector<int, std::allocator<int> > const&)
  0.00      1.42     0.00      100     0.00     3.57  TestSet(std::vector<int, std::allocator<int> > const&)

因此使用矢量更快,但差别不大。