将元素随机插入向量时随机减速

Posted

技术标签:

【中文标题】将元素随机插入向量时随机减速【英文标题】:Random slowdown when inserting elements at random into vectors 【发布时间】:2013-12-14 11:46:47 【问题描述】:

编辑: 我已经修复了插入。正如 Blastfurnace 友好地提到的那样,插入使迭代器无效。我认为需要循环来比较性能(请参阅我对 Blastfurnance 答案的评论)。我的代码已更新。我对列表有完全相似的代码,只是用列表替换了向量。但是,通过代码,我发现对于小型和大型数据类型,甚至对于线性搜索(如果我删除插入),列表的性能都比向量好。根据http://java.dzone.com/articles/c-benchmark-%E2%80%93-stdvector-vs 和其他网站不应该这样。有什么线索可以说明吗?

我正在学习数学软件编程课程(周一考试),为此我想展示一个图表,比较将元素随机插入向量和列表之间的性能。但是,当我测试代码时,我会随机减速。例如,我可能有 2 次迭代,其中将 10 个元素随机插入到大小为 500 的向量中需要 0.01 秒,然后是 3 次类似的迭代,每次大约需要 12 秒。这是我的代码:

    void AddRandomPlaceVector(vector<FillSize> &myContainer, int place)  
    int i = 0;

    vector<FillSize>::iterator iter = myContainer.begin();

    while (iter != myContainer.end())
    
        if (i == place)
        
            FillSize myFill;
            iter = myContainer.insert(iter, myFill);
        
        else
            ++iter;

        ++i;
    

    //cout << i << endl;


double testVector(int containerSize, int iterRand)

    cout << endl;
    cout << "Size: " << containerSize << endl << "Random inserts: " << iterRand << endl;

    vector<FillSize> myContainer(containerSize);
    boost::timer::auto_cpu_timer tid;

    for (int i = 0; i != iterRand; i++)
    
        double randNumber = (int)(myContainer.size()*((double)rand()/RAND_MAX));
        AddRandomPlaceVector(myContainer, randNumber);
    

    double wallTime = tid.elapsed().wall/1e9;

    cout << "New size: " << myContainer.size();

    return wallTime;


int main()

    int testSize = 500;
    int measurementIters = 20;
    int numRand = 1000;
    int repetionIters = 100;


    ofstream tidOutput1_sum("VectorTid_8bit_sum.txt");
    ofstream tidOutput2_sum("ListTid_8bit_sum.txt");

    for (int i = 0; i != measurementIters; i++)
    
        double time = 0;

        for (int j = 0; j != repetionIters; j++) 
            time += testVector((i+1)*testSize, numRand);
        

        std::ostringstream strs;
        strs << double(time/repetionIters);
        tidOutput1_sum << ((i+1)*testSize) << "," << strs.str() << endl;
    

    for (int i = 0; i != measurementIters; i++)
    
        double time = 0;

        for (int j = 0; j != repetionIters; j++) 
            time += testList((i+1)*testSize, numRand);
        

        std::ostringstream strs;
        strs << double(time/repetionIters);
        tidOutput2_sum << ((i+1)*testSize) << "," << strs.str() << endl;
    
    return 0;


struct FillSize

    double fill1;
;

该结构只是为了让我轻松添加更多值,以便我可以测试不同大小的元素。我知道这段代码在性能测试方面可能并不完美,但他们宁愿让我做一个简单的例子,也不愿简单地引用我发现的东西。

我现在已经在两台计算机上测试了这段代码,它们都有同样的问题。怎么可能?你能帮我解决一下,这样我就可以绘制它并在星期一展示它吗?也许在每次迭代之间增加几秒钟的等待时间会有所帮助?

亲切的问候, 比亚克

【问题讨论】:

AddRandomPlaceVector 应该是 myContainer.insert(myContainer.begin()+place, myFill); 那个 for 循环很慢而且不需要。虽然不是 12 秒慢。如果你的矢量大小真的是 500,那么这里什么都不需要 12 秒。 感谢 Dave,请查看我对 Blastfurnace 的回答的编辑和评论。也许你也可以给我一个提示? 【参考方案1】:

您的AddRandomPlaceVector 函数存在严重缺陷。使用insert()invalidate iterators 所以for 循环是无效代码。

如果您知道所需的插入点,则根本没有理由遍历 vector

void AddRandomPlaceVector(vector<FillSize> &myContainer, int place)

    FillSize myFill;
    myContainer.insert(myContainer.begin() + place, myFill);

【讨论】:

啊,当然。我想到了这一点,但后来我会在向量和列表之间的比较中使用向量的随机访问功能。因为我的比较应该说明线性搜索(检查条件),所以这会扭曲性能。但是,我会考虑不使我的迭代器失效! 所以我更新了我的原始帖子,但发现了另一个问题。也许你也可以帮助我? :) @user1452257:您正在测试优化/发布版本吗? list 代码是否也在插入时遍历 整个 列表?如果随机插入是主要操作,我不得不说std::vector 是一个糟糕的容器选择。 不,我正在测试 CodeBlocks 中的“调试”构建,没有任何优化工作。可能就是这样。列表的代码完全相同。我可以让代码不遍历整个容器,但我想如果它在两个容器上是相同的操作,那我就无所谓了。我的想法是“恰好有一个元素符合条件”,但代码应该类似于条件搜索算法。根据***.com/questions/238008/… 的说法,我认为矢量会更快。 @user1452257:哦,是的,分析未优化的构建不是一个好主意。标准库容器和算法严重依赖模板,并且真正受益于编译器优化。

以上是关于将元素随机插入向量时随机减速的主要内容,如果未能解决你的问题,请参考以下文章

std :: deque(双端队列)真的是随机访问和恒定时间插入吗?

随机选择一个空向量元素,当可以预先知道哪些是满的

生成两个相关的随机向量

如何从向量中随机删除一个元素?

常数时间插入删除和获取随机元素

从长(且合理)稀疏向量中选择随机元素的最有效方法是啥?