次のロジックを使用して、コレクションをループしてMapデータ構造に挿入します。
- 整数がまだマップに挿入されていない場合は、key = integer、value=1を挿入します。
- キーが存在する場合は、値をインクリメントします。
Javaには、HashMapとTreeMapの2つのマップがあります。これらを以下で比較します。
HashMapとTreeMap
必要に応じて、詳細な説明をスキップして、要約に直接ジャンプできます。
HashMapは、キーと値のペアを配列に格納するマップです。キーkに使用されるインデックスは次のとおりです。
2つの完全に異なるキーが同じインデックスになる場合があります。これを解決するために、配列内の各場所は実際にはリンクリストです。つまり、すべてのルックアップは常にリンクリストをループし、k.equals(other)メソッドを使用して等しいかどうかをチェックする必要があります。最悪の場合、すべてのキーが同じ場所に保存され、HashMapはインデックス付けされていないリストになります。
HashMapがより多くのエントリを取得すると、これらの衝突の可能性が高まり、構造の効率が低下します。これを解決するために、エントリの数がクリティカルポイント(コンストラクターのloadFactor引数によって決定される)に達すると、構造のサイズが変更されます。
- 新しいアレイは、現在のサイズの約2倍で割り当てられます
- ループは既存のすべてのキーに対して実行されます
- キーの場所が新しい配列に対して再計算されます
- キーと値のペアが新しい構造に挿入されます
ご覧のとおり、サイズ変更が多い場合、これは比較的コストがかかる可能性があります。
この問題は、開始する前に適切なサイズでHashMapを事前に割り当てることができれば、克服できます。たとえば、map = new HashMap(input.size()* 1.5)です。大規模なデータセットの場合、これによりメモリチャーンを大幅に減らすことができます。
キーは基本的にHashMap内でランダムに配置されるため、キーイテレーターはランダムな順序でキーを反復処理します。Javaは、キーが挿入された順序で反復するLinkedHashMapを提供します。
HashMapのパフォーマンス:
- ハッシュの正しいサイズと適切な分布を考えると、ルックアップは一定時間です。
- 分布が悪いと、パフォーマンスは(最悪の場合)線形探索-O(n)に低下します。
- 初期サイズが悪いと、パフォーマンスは再ハッシュのパフォーマンスになります。これを簡単に計算することはできませんが、良くありません。
OTOH a TreeMapは、エントリをバランスの取れたツリーに格納します。動的構造は、キーと値のペアが追加されるにつれて段階的に構築されます。挿入はツリーの深さ(log(tree.size())に依存しますが、予測可能です。HashMapとは異なり、中断やパフォーマンスが低下するエッジ条件はありません。
十分に分散されたHashMapを考えると、各挿入とルックアップはより高価です。
さらに、キーをツリーに挿入するには、すべてのキーが他のすべてのキーと比較可能である必要があり、Comparableインターフェイスのk.compare(other)メソッドが必要です。明らかに、質問が整数に関するものであることを考えると、これは問題ではありません。
TreeMapのパフォーマンス:
- n個の要素の挿入はO(n log n)です
- ルックアップはO(log n)です
概要
最初の考え:データセットのサイズ:
- 小さい場合(1000年代と10,000年代でも)、最新のハードウェアでは実際には問題になりません。
- マシンがメモリ不足になるほど大きい場合は、TreeMapが唯一のオプションである可能性があります
- そうでなければ、サイズはおそらく決定要因ではありません
この特定のケースでは、重要な要素は、データセット全体のサイズと比較して、予想される一意の整数の数が多いか少ないかです。
- 小さい場合、全体の時間は小さいセットでのキールックアップによって支配されるため、最適化は関係ありません(ここで停止できます)。
- 大きい場合、全体の時間は挿入によって支配され、決定はより多くの要因に依存します。
- データセットのサイズは既知ですか?
- はいの場合:HashMapを事前に割り当てることができるため、メモリチャーンが排除されます。これは、hashCode()メソッドが高価な場合(この場合ではない)に特に重要です。
- いいえの場合:TreeMapはより予測可能なパフォーマンスを提供し、より適切な選択となる可能性があります
- リアルタイムシステムやGUIのイベントスレッドなど、大きなストールを必要としない予測可能なパフォーマンスはありますか?
- はいの場合:TreeMapは、ストールなしではるかに優れた予測可能性を提供します
- いいえの場合:HashMapは、おそらく計算全体の全体的なパフォーマンスを向上させます
上からの圧倒的なポイントがない場合の最後のポイント:
- ソートされた値のキーのリストはありますか?
- はいの場合(たとえば、ヒストグラムを印刷する場合):TreeMapはすでにキーをソートしているため、便利です。
ただし、パフォーマンスが重要な場合、決定する唯一の方法は、Mapインターフェースに実装し、HashMapとTreeMapの両方をプロファイリングして、どちらが実際に状況に適しているかを確認することです。時期尚早の最適化は多くの悪の根源です:)