【问题标题】:"remove one element" from unordered_set using erase(begin()) is slow in gcc使用擦除(开始())从 unordered_set 中“删除一个元素”在 gcc 中很慢
【发布时间】:2012-04-17 16:46:21
【问题描述】:

我想要一个从 unordered_set 中“删除一个元素”的函数。

但是,当它使用erase(begin()) 实现时,它变得非常慢。 (这是在 g++-4.5.3 中;也许 begin() 必须遍历更多的空哈希桶?)

请参阅下面的示例代码,其中包含令人惊讶的时序。

有没有其他方法来实现“删除一个元素”效率更高? (我确实希望允许其他会导致迭代器无效的干预集合操作。)

#include <unordered_set>
#include <iostream>
#include <chrono>
using namespace std;

struct Timer {
    Timer(string s) : _s(s), _start(Clock::now()) { }
    ~Timer() {
        auto t=chrono::duration_cast<chrono::milliseconds>(Clock::now()-_start).count();
        cerr << "Timer(" << _s << ") = " << t << "ms\n";
    }
 private:
    typedef chrono::high_resolution_clock Clock;
    string _s;
    Clock::time_point _start;
};

int main()
{
    unordered_set<int> s;
    const int num=200000;
    { Timer t("insert"); for (int i=0;i<num;i++) { s.insert(i); } }
    { Timer t("remove half"); for (int i=0;i<num/2;i++) { s.erase(s.begin()); } }
    long long s1=0, s2=0;
    { Timer t("access begin()"); for (int i=0;i<num/2;i++) { s1+=*s.begin(); } }
    { Timer t("access all"); for (auto it=s.begin();it!=s.end();++it) { s2+=*it; } }
    cerr << s1 << " " << s2 << "\n";
    return 0;
}

// Timer(insert) = 36ms
// Timer(remove half) = 3039ms
// Timer(access begin()) = 5958ms
// Timer(access all) = 1ms

【问题讨论】:

  • 这个测试一个接一个地删除了很多元素,中间没有做任何其他事情。这可能不是您的实际程序的行为方式。请描述您的更大目标;可能你应该使用 unordered_set 以外的东西。
  • 您想优化从 unordered_set 中删除一个元素还是删除 N 个元素?

标签: c++ erase unordered-set


【解决方案1】:

该版本的 GNU 库似乎存在问题,在较新的版本中已修复。以下是我的测试结果,使用我碰巧安装的两个版本:

mikes@seymour-desktop:~$ g++-4.4.5 -std=c++0x -O3 test.cpp
mikes@seymour-desktop:~$ ./a.out 
Timer(insert) = 15ms
Timer(remove half) = 3815ms
Timer(access begin()) = 7722ms
Timer(access all) = 0ms
10000000000 14999950000

mikes@seymour-desktop:~$ g++-4.6.1 -std=c++0x -O3 test.cpp
mikes@seymour-desktop:~$ ./a.out 
Timer(insert) = 16ms
Timer(remove half) = 2ms
Timer(access begin()) = 0ms
Timer(access all) = 1ms
10000000000 14999950000

通过使用boost::unordered_set,我也获得了类似的快速结果,因此如果您无法更新编译器,这是一个选项。

【讨论】:

  • 谢谢迈克。那我就期待下一个版本的编译器吧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-29
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多