Javaプログラミングに10年近く携わっていて、今までまじめにHashMap/TreeMap/LinkedHashMapの違いを勉強したことがなかったので、簡単にまとめてみました。Oracle JDK 1.7.0.25 のソースも参照しています。
なお、あんまり学術的に突っ込んで調べてないので、話半分程度に考えて、正確な情報についてはJDKのJavaDocやソースコードを参照してください。
HashMap, HashSet
- キーとなるオブジェクトのhashCode()をハッシュテーブルに振り分けて格納してく実装。
- JDK 1.7.0.25の内部実装としては、hashCode()を元にして配列アクセス出来る"table"が用意されてる。配列アクセス=Javaの配列として用意されていて、どの配列要素にも一定のコスト(あんまり厳密に書いてないので、パフォーマンスというか感覚的な話)でアクセス出来る。hashCode()の計算量に引きずられるのかな?
- デフォルトのコンストラクタではそれほど広大なハッシュテーブルを用意しているわけではなく、埋まり具合に応じて拡張・再構築される。一応、ハッシュテーブルの初期容量と、拡張・再構築を実施する埋まり具合を指定するコンストラクタも用意されている。
- HashSetは内部的にはHashMapをそのまま使っていて、単に値としてダミーのオブジェクトを入れて、キーとしての操作だけをSetインターフェイスの実装として公開してるようです。
HashMapでput()にかかる時間、get()にかかる時間を見てみるサンプル:
TreeMap, TreeSet
- 赤黒木・・・つまり平衡2分探索木の一種で、それを使ってソートされた状態でキー(と値)を保存出来る。
- キーを指定する containsKey(), get(), put(), remove() メソッドは、使用されているアルゴリズムの特性から時間コストはlog(n)になる・・・つまり、平衡2分探索になりますよーということらしいです・・・。
- やはり特徴としては、要素を追加すると自動的に自然順序 or コンストラクタで指定するComparatorによってソートされ、iteratorなどで要素を取り出すときもソートされた順序で取り出される点でしょうか。
- 赤黒木の実装はそれなりに大変で、JDK 1.7.0.25 の内部実装でもコメント含めておよそ2,400行になっています。HashMapがおよそ1,100行ですから、その2倍のソースコードが必要になっています。
- 内部の赤黒木に対して複雑な操作が必要になってくるため、要素の追加ではHashMapより計算量が多くなってしまっています。
- HashSetと同様、TreeSetも内部的にはTreeMapを使っていて、単に値としてダミーのオブジェクトを入れて、キーとしての操作だけをSetインターフェイスの実装として公開してるようです。
参考:
- 赤黒木 - Wikipedia
- Red-Black Tree by Java -- これで分かった赤黒木
TreeMapでput()にかかる時間、get()にかかる時間を見てみるサンプル:
LinkedHashMap, LinkedHashSet
- HashMapですと、hashCode()を元に順番が並べ替えられてしまいますが、LinkedHashMapを使うと、要素を追加した順番で値を取り出すことが出来ます。
- 仕掛けとしては要素(エントリ)に対して二重リンク・リストを保持しておき、Iteratorなどで取り出すときに二重リンク・リストを辿るようにしている。
- なお、要素を追加した順序ではなく、要素に「アクセス」(get()含む)した順を保持するよう指定できるコンストラクタが提供されている。これを使うと、単にget()するだけでも、要素が入っていればアクセス順として内部のリンクリストの構成が更新される。
- LinkHashSetについては、上と同様、LinkedHashMapを使って実現してます。
LinkedHashMapでput()にかかる時間、get()にかかる時間を見てみるサンプル:
Java配列, ArrayList, LinkedList
ちょっと脇道にそれますが、リスト管理の仕組みとしてJavaの配列, ArrayList, LinkedListを比べてみました。
Java配列のデモ:
ArrayListのデモ:
LinkedListのデモ:
簡単なベンチマークプログラムを組んでみますと、HashMap/TreeMap/LinkedHashMapの実装による差異が目で見えるようになり、面白かったです。
今回は時間だけに着目したベンチマークプログラムを作ってみましたが、メモリ容量に着目してみるのも面白いかもしれません。
プレーンテキスト形式でダウンロード
コメント