C++ 0xはboost
および他の多くの場所で利用可能な_unordered_set
_を導入しています。私が理解しているのは、_unordered_set
_がO(1)
ルックアップの複雑さを持つハッシュテーブルであることです。一方、set
は、log(n)
ルックアップの複雑さを持つツリーに他なりません。 なぜ一体誰が_unordered_set
_の代わりにset
を使用するのでしょうか?つまり、set
の必要性はもうありませんか?
セットのアイテムを繰り返し処理する場合、順序が重要です。
順序なしセットは、いくつかの方法でO(1)平均アクセス時間に対価を支払う必要があります。
set
は、unordered_set
よりも lessメモリを使用して、同じ数の要素を格納します。set
のルックアップはunordered_set
のルックアップよりも高速になる可能性があります。unordered_set
の平均ケースで高速ですが、多くの場合、の最悪ケースの方が保証されていますset
の複雑度(たとえば、insert
)。set
は要素をソートします順番にアクセスしたい場合に便利です。set
sを<
、<=
、>
および>=
と辞書的に比較できます。これらの操作をサポートするためにunordered_set
sは必要ありません。ハッシュテーブルよりもツリーを好むときはいつでも。
たとえば、最悪の場合、ハッシュテーブルは「O(n)」です。 O(1)は平均的なケースです。ツリーは最悪でも "O(log n)"です。
スイープラインアルゴリズムを検討してください。これらのアルゴリズムはハッシュテーブルでは完全に失敗しますが、バランスの取れたツリーでは美しく機能します。スイープラインアルゴリズムの具体例を示すために、フォーチュンのアルゴリズムを検討してください。 http://en.wikipedia.org/wiki/Fortune%27s_algorithm
Std :: setは標準C++の一部であり、unordered_setはそうではないためです。 C++ 0xは標準ではなく、どちらもBoostではありません。私たちの多くにとって、移植性は不可欠であり、それは標準に固執することを意味します。
次の場合にセットを使用:
次の場合にunordered_setを使用します:
例:
セットする:
入力:1、8、2、5、3、9
出力:1、2、3、5、8、9
Unordered_set:
入力:1、8、2、5、3、9
出力:9 3 1 8 2 5(この順序は、ハッシュ関数の影響を受ける可能性があります)
主に違い:
注:(場合によってはset
の方が便利です)たとえばvector
をキーとして使用する
set<vector<int>> s;
s.insert({1, 2});
s.insert({1, 3});
s.insert({1, 2});
for(const auto& vec:s)
cout<<vec<<endl; // I have override << for vector
// 1 2
// 1 3
set
がvector<int>
をオーバーライドするため、operator<
をvector
のキーとして使用できる理由。
ただし、unordered_set<vector<int>>
を使用する場合、vector<int>
のハッシュ関数を作成する必要があります。ベクターにはハッシュ関数がないため、次のように定義する必要があります。
struct VectorHash {
size_t operator()(const std::vector<int>& v) const {
std::hash<int> hasher;
size_t seed = 0;
for (int i : v) {
seed ^= hasher(i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
return seed;
}
};
vector<vector<int>> two(){
//unordered_set<vector<int>> s; // error vector<int> doesn't have hash function
unordered_set<vector<int>, VectorHash> s;
s.insert({1, 2});
s.insert({1, 3});
s.insert({1, 2});
for(const auto& vec:s)
cout<<vec<<endl;
// 1 2
// 1 3
}
場合によってはunordered_set
がより複雑であることがわかります。
主に引用元: https://www.geeksforgeeks.org/set-vs-unordered_set-c-stl/https://stackoverflow.com/a/29855973/6329006 =
申し訳ありませんが、並べ替えられたプロパティについてもう1つ注目する価値があります。
必要な場合コンテナー内のデータの範囲、たとえば:setに時間を保存し、2013年からの時間を必要とする場合-01-01から2014-01-01。
nordered_setの場合、不可能です。
もちろん、この例は、mapとnordered_mapの間の使用例についてより説得力があります。
他の人々がすでに言及したことに加えて、もう一つ。要素をunordered_setに挿入するために予想される償却された複雑さはO(1)ですが、時々will take O(n)再構成する必要があります(バケットの数を変更する必要があります)-「良い」ハッシュ関数を使用する場合でも、ベクトルに要素を挿入するのと同じようにO(n)基礎となる配列を再割り当てする必要があります。
セットへの挿入には常に最大でO(log n)が必要です。これは、一部のアプリケーションでは望ましい場合があります。
g++
6.4 stdlibc ++順序付きvs順序なしセットベンチマーク
この支配的なLinux C++実装のベンチマークを行い、違いを確認しました。
完全なベンチマークの詳細と分析は次の場所にあります: C++のSTLセットの基礎となるデータ構造は何ですか? ここでは繰り返しません。
「BST」は「std::set
でテスト済み」を意味し、「ハッシュマップ」は「std::unordered_set
でテスト済み」を意味します。 「ヒープ」はstd::priority_queue
用で、次の場所で分析しました: ヒープvsバイナリ検索ツリー(BST)
簡単な要約として:
グラフは、これらの条件下では、100,000を超えるアイテムがある場合、ハッシュマップの挿入が常にずっと速く、アイテムの数が増えるにつれて差が大きくなることを明確に示しています
この速度向上のコストは、効率的に順番に移動できないことです。
曲線は、順序付けられたstd::set
がBSTベースであり、std::unordered_set
がハッシュマップベースであることを明確に示唆しています。参考回答では、GDBのステップによってコードをデバッグすることをさらに確認しました。
map
vs unordered_map
に対する同様の質問: 些細なキーの場合にunordered_mapよりもmapを使用する利点はありますか?
それとは別に、別の形式に変換したい場合は、関係を持たせるのが便利だと思います。
また、アクセスは高速ですが、インデックスの作成時間や、インデックスの作成やアクセスに使用されるメモリが長くなる可能性があります。
ソートしたい場合は、unordered_setの代わりにsetを使用します。 unordered_setは、保存された順序が問題にならない場合にsetで使用されます。