特定の操作について stl map と stl unordered_map を比較しようとしています。ネットで調べてみると、どれが全体的に優れているかという疑問が増すばかりです。そこで、両者が実行する操作に基づいて比較したいと思います。
どちらがより速く実行されますか
挿入、削除、検索
メモリからクリアするのに必要なメモリが少なく、時間が短いのはどれですか。どんな説明でも大歓迎です!!!
前もって感謝します
特定の操作について stl map と stl unordered_map を比較しようとしています。ネットで調べてみると、どれが全体的に優れているかという疑問が増すばかりです。そこで、両者が実行する操作に基づいて比較したいと思います。
どちらがより速く実行されますか
挿入、削除、検索
メモリからクリアするのに必要なメモリが少なく、時間が短いのはどれですか。どんな説明でも大歓迎です!!!
前もって感謝します
挿入、削除、ルックアップでパフォーマンスが速いのはどれですか?どちらがメモリからそれをクリアするのに必要なメモリと時間が少なくて済みます。説明は大歓迎です!!!
特定の用途については、実際のデータと使用パターンの両方を試して、どちらが実際に速いかを確認する必要があります...どちらかが常に「勝つ」と想定するのは危険な十分な要因があります。
学術的に-要素の数が無限に向かって増加するにつれて、std::unordered_map
(コンピューティングサイエンスが「ハッシュマップ」または「ハッシュテーブル」と呼ぶものを提供するC ++ライブラリである)に対するこれらの操作は、同じ時間かかる傾向がありますO (1)(メモリ制限/キャッシングなどを無視)、一方std::map
(平衡二分木)では、要素の数が2倍になるたびに、通常、追加の比較操作を行う必要があるため、O(log 2 n )。
std::unordered_map
実装では必然的にオープンハッシュを使用します。基本的な期待は、「バケット」の連続した配列があり、それぞれが論理的にハッシュする値のコンテナであるということです。
これは通常、ハッシュテーブルをvector<list<pair<key,value>>>
、ベクトル要素から値への取得に、バケットに格納されているリストヘッドポインターを最初のリストノードまでたどるときに、少なくとも1つのポインター逆参照が含まれる場所として描写するのに役立ちます。挿入/検索/削除操作のパフォーマンスは、リストのサイズに依存します。これは、平均してunordered_map
'sに等しくなりload_factor
ます。
をmax_load_factor
下げると(デフォルトは1.0)、衝突は少なくなりますが、挿入中の再割り当て/再ハッシュが増え、メモリの浪費が増えます(キャッシュミスの増加によりパフォーマンスが低下する可能性があります)。
この最も明白なunordered_map
実装のメモリ使用量には、リストヘッドイテレータ/ポインタサイズのバケットの連続した配列と、bucket_count()
キー/値ペアごとに1つの二重リンクリストノードの両方が含まれます。通常、bucket_count()
+ 2 *size()
オーバーヘッドの追加のポインターであり、実装が実行する可能性のある動的メモリ割り当て要求サイズの切り上げに合わせて調整されます。たとえば、100バイトを要求すると、128、256、または512になる可能性があります。実装の動的メモリルーチンは、割り当てられた/使用可能な領域を追跡するためにメモリを使用する場合もあります。
それでも、C ++標準は、実際の実装が独自のパフォーマンス/メモリ使用量の決定を行う余地を残しています。たとえば、新しい大きな配列を割り当てた後、バケットの古い連続配列をしばらく保持することができるため、後者への値の再ハッシュを徐々に実行して、平均的なパフォーマンスを犠牲にして、最悪の場合のパフォーマンスを減らすことができます。両方のアレイは、操作中に参照されます。
Amap
は二分木であり、へのさまざまな呼び出しによって返される個別のヒープメモリ領域をリンクするポインタを使用することが期待できますnew
。キー/値データと同様に、ツリー内の各ノードには、親、左、および右のポインターが必要です(失われた場合は、ウィキペディアのバイナリツリーの記事を参照してください)。
したがって、キー/値のペアにノードを割り当てる必要がunordered_map
ありmap
ます。前者は通常、前/次のノードのリンケージに2つのポインター/イテレーターのオーバーヘッドがあり、後者は親/左/右に3つあります。ただし、unordered_map
さらにバケット用の単一の連続した割り当てがありますbucket_count()
(== size()
/ load_factor()
)。
ほとんどの場合、これはメモリ使用量の劇的な違いではなく、1つの余分な領域の割り当て解除の時間差が目立つことはほとんどありません。
コンテナが前もって入力され、それ以上挿入/消去せずに繰り返し検索される場合は、標準アルゴリズム、、、を使用して検索されたソート済みベクトルを使用するのが最も速い場合がbinary_search
あります。これには、単一の連続したメモリ割り当てという利点があり、キャッシュにはるかに適しています。常に優れていますが、それでも高速である可能性があります。気になる場合は測定してください。equal_range
lower_bound
upper_bound
map
unordered_map
両方あるのは、全体としてどちらが優れているというわけではないからです。
どちらかを使用してください。他の方が使用に適していることが判明した場合は切り替えてください。
あなたの質問に対する答えは、使用している特定の STL 実装に大きく依存しています。本当に、STL 実装のドキュメントを確認する必要があります。おそらく、パフォーマンスに関するかなりの量の情報が含まれているはずです。
ただし、一般に、cppreference.com によると、マップは通常、赤黒木として実装され、時間計算量 O(log n) の操作をサポートしますが、unordered_mapsは通常、一定時間の操作をサポートします。cppreference.com では、メモリ使用量に関する洞察はほとんど提供されていません。ただし、別の StackOverflow の回答は、マップが一般的に unordered_maps よりも少ないメモリを使用することを示唆しています。
Visual Studio 2012 を使用した STL 実装 Microsoft パッケージの場合、mapは償却された O(log n) 時間でこれらの操作をサポートし、unordered_mapは償却された定数時間でそれらをサポートしているようです。ただし、ドキュメントには、メモリ フットプリントについて明示的な記述はありません。
地図:
挿入:
消す:
調べる:
順序付けられていないマップ:
挿入:
消す:
調べる:
これらを知っていれば、実装のタイプに応じて使用するコンテナーを決定できます。
ソース: www.cplusplus.com