2

unordered_set から「要素を 1 つ削除」する機能が欲しいです。

ただし、erase(begin()) を使用して実装すると、非常に遅くなります。(これは g++-4.5.3 にあります。begin() はより多くの空のハッシュ バケットをトラバースする必要があるのでしょうか?)

驚くべきタイミングで以下のサンプル コードを参照してください。

より効率的な「1つの要素を削除する」を実装する他の方法はありますか? (イテレータを無効にする他の介入セット操作を許可したい。)

#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
4

1 に答える 1

6

そのバージョンの GNU ライブラリの問題のようで、最近のバージョンでは修正されています。たまたまインストールした2つのバージョンを使用したテストの結果は次のとおりです。

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ので、コンパイラを更新できない場合のオプションです。

于 2012-04-17T17:03:38.740 に答える