web-dev-qa-db-ja.com

std :: mapとstd :: unordered_mapの選択

stdunordered_mapに実際のハッシュマップを持っているので、実際に存在するシステムでunordered_mapよりも古くmapを使用する理由(またはいつ)を使用したいのか?すぐに見ることができない明らかな状況はありますか?

129
Johann Gerell

既に言及 のように、mapはソートされた方法で要素を反復することができますが、unordered_mapはできません。これは、コレクション(アドレス帳など)の表示など、多くの状況で非常に重要です。これは、(1)find()によって返されるイテレータから反復を開始する、または(2)lower_bound()などのメンバー関数の存在など、他の間接的な方法でも現れます。

また、最悪の場合searchの複雑さにいくつかの違いがあると思います。

  • mapの場合、O(lg N)

  • unordered_mapの場合、O(N)[このmayは、ハッシュ関数が良くないためにハッシュ衝突が多すぎる場合に発生します。]

同じことが、最悪の場合deletionの複雑さにも当てはまります。

108
Arun

上記の回答に加えて、unordered_mapが一定速度(O(1))であるという理由だけで、map(次数log(N))よりも高速であることも意味しないことに注意してください。 。特にNは2に制限されているため、定数はlog(N)よりも大きくなる可能性があります32 (または264)。

そのため、他の回答(mapは順序を維持し、ハッシュ関数は難しい場合があります)に加えて、mapの方がパフォーマンスが高い可能性があります。

たとえば、私が ブログ投稿 で実行したプログラムでは、VS10ではstd::unordered_mapstd::mapよりも遅いことがわかりました(ただし、boost::unordered_mapは両方よりも高速でした)。

Performance Graph

3番目から5番目のバーに注意してください。

85
Motti

これは、GoogleのChandler Carruthによる CppCon 2014講義 によるものです。

std::mapは(多くの人が考えている)パフォーマンス指向の作業には役に立たない:O(1)で償却したアクセスが必要な場合は、適切な連想配列を使用します(または1つがない場合はstd::unorderded_map) ;ソートされた順次アクセスが必要な場合は、ベクトルに基づいたものを使用してください。

また、std::mapはバランスの取れたツリーです。信じられないほど頻繁にトラバースするか、バランスを取り直す必要があります。これらはそれぞれ、キャッシュキラーとキャッシュアポカリプスの操作です... std::mapに対してNOとだけ言ってください。

効率的なハッシュマップの実装に関する this SO question に興味があるかもしれません。

(PS-std::unordered_mapは、リンクリストをバケットとして使用するため、キャッシュに適さない。)

25
einpoklum

マップ内のアイテムをソート順に繰り返す必要があるstd::mapを使用することは明らかだと思います。

また、ハッシュ関数(一般的に非常に直感的ではない)の代わりに、比較演算子(直感的)を作成する場合にも使用できます。

21
Ken Bloom

非常に大きなキー、おそらく大きな文字列があるとします。大きな文字列のハッシュ値を作成するには、文字列全体を最初から最後まで処理する必要があります。キーの長さに対して少なくとも直線的な時間がかかります。ただし、キーの>演算子を使用してバイナリツリーのみを検索する場合、最初の不一致が見つかった場合、各文字列比較は返すことができます。これは通常、大きな文字列では非常に早い段階です。

この推論は、std::unordered_mapおよびstd::mapfind関数に適用できます。キーの性質がハッシュを生成するのに時間がかかる場合(std::unordered_mapの場合)、バイナリ検索を使用して要素の場所を見つけるのにかかる時間(std::mapの場合) )、std::mapでキーを検索する方が高速です。これが当てはまるシナリオは簡単に考えられますが、実際には非常にまれです。

9
Martin G