C ++ 0xは、他の多くの場所でunordered_set利用可能なものを導入していますboost。私が理解しているのunordered_setは、O(1)ルックアップが複雑なハッシュテーブルです。一方、ルックアップが複雑なsetツリーにすぎませんlog(n)。なぜ誰もがset代わりに使うのunordered_setでしょうか?すなわち、setもはや必要性はありますか?
C ++ 0xは、他の多くの場所でunordered_set利用可能なものを導入していますboost。私が理解しているのunordered_setは、O(1)ルックアップが複雑なハッシュテーブルです。一方、ルックアップが複雑なsetツリーにすぎませんlog(n)。なぜ誰もがset代わりに使うのunordered_setでしょうか?すなわち、setもはや必要性はありますか?
回答:
セットのアイテムを繰り返し処理したい人にとって、順序は重要です。
< >ますか?
順序付けされていないセットは、いくつかの方法でO(1)平均アクセス時間を支払う必要があります。
set同じ数の要素を格納するよりも少ないメモリを使用しunordered_setます。setあるかもしれないより高速での検索よりもunordered_set。unordered_set、彼らはしばしば持つことが保証されている優れた最悪の複雑さをするためにset(例えばinsert)。set 要素がソートあなたが順序でそれらにアクセスする場合に便利です。setとSを<、<=、>と>=。unordered_setこれらの操作をサポートするためには必要ありません。<)。
ハッシュテーブルよりもツリーを好むときはいつでも。
たとえば、ハッシュテーブルは最悪の場合 "O(n)"です。O(1)は平均的なケースです。木は最悪の場合「O(log n)」です。
次の場合にセットを使用:
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
オーバーライドのためにvector<int>キーとして使用できる理由。setvectoroperator<
ただし、を使用するunordered_set<vector<int>>場合は、のハッシュ関数を作成する必要があります。これはvector<int>、vectorにはハッシュ関数がないため、次のように定義する必要があるためです。
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
std :: setは標準C ++の一部であり、unordered_setはそうではないためです。C ++ 0xは標準ではなく、Boostも標準ではありません。私たちの多くにとって、移植性は不可欠であり、それは標準に固執することを意味します。
スイープラインアルゴリズムを検討してください。これらのアルゴリズムはハッシュテーブルでは完全に失敗しますが、バランスの取れたツリーでは美しく機能します。スイープラインアルゴリズムの具体例を示すために、フォーチュンのアルゴリズムを考えてみましょう。http://en.wikipedia.org/wiki/Fortune%27s_algorithm
g++ 6.4 stdlibc ++の順序付きと順序なしのセットのベンチマーク
この主要なLinux C ++実装をベンチマークして、違いを確認しました。
完全なベンチマークの詳細と分析は、C ++のSTLセットの基本的なデータ構造は何ですか?ここでは繰り返しません。
「BST」は「テスト済み」を意味しstd::set、「ハッシュマップ」は「テスト済み」を意味しstd::unordered_setます。「ヒープ」はstd::priority_queue私が分析したものです:ヒープとバイナリ検索ツリー(BST)
簡単な要約として:
グラフは、これらの条件下では、10万を超えるアイテムがある場合、ハッシュマップの挿入は常にはるかに高速であり、アイテムの数が増えるにつれて差が大きくなることを明確に示しています
この速度向上のコストは、順番に効率的に移動できないことです。
曲線は、ordered std::setがBSTベースでstd::unordered_setハッシュマップベースであることを明確に示唆しています。参考回答では、GDBステップによってコードをデバッグしていることをさらに確認しました。
mapvs に対する同様の質問unordered_map:些細なキーの場合にunordered_mapよりもmapを使用する利点はありますか?
一方で、別の形式に変換したい場合は、関係にあると便利です。
また、アクセスは高速ですが、インデックスを作成する時間や、インデックスの作成やアクセスに使用されるメモリが長くなる可能性もあります。
この回答は10年遅れる可能性がありますstd::unordered_setが、セキュリティの欠点もあることを指摘しておく価値があります。
ハッシュ関数が予測可能である場合(これは、ランダム化されたソルトなどの対策を適用しない限り、通常これに該当します)、攻撃者はハッシュの衝突を生成し、すべての挿入とルックアップにO(n)時間を要するデータを手作業で作成できます。
これは非常に効率的で洗練されたサービス拒否攻撃に使用できます。
内部でハッシュマップを使用する言語の多くの(ほとんど?)実装がこれに遭遇しました: