同意する:
- O(1)の一般的な償却後の複雑さ
- 不適切な
hashCode()
実装は、複数の衝突を引き起こす可能性があります。つまり、最悪の場合、すべてのオブジェクトが同じバケットに移動するため、各バケットがによってサポートされている場合はO(N)になりList
ます。
- Java 8以降、
HashMap
動的に各バケットで使用されるノード(リンクされたリスト)をTreeNodes(リストが8要素を超えると赤黒ツリー)に置き換えられ、O(logN)の最悪のパフォーマンスになります。
しかし、100%正確にしたい場合、これは完全な真実ではありません。hashCode()
キーの実装とキーのタイプObject
(不変/キャッシュまたはコレクション)も、厳密な意味で実際の複雑さに影響を与える可能性があります。
次の3つのケースを想定します。
HashMap<Integer, V>
HashMap<String, V>
HashMap<List<E>, V>
彼らは同じ複雑さを持っていますか?まあ、最初のものの償却済みの複雑さは、予想通り、O(1)です。ただし、残りの部分ではhashCode()
、ルックアップ要素の計算も必要です。つまり、アルゴリズムで配列とリストを走査する必要があるかもしれません。
上記のすべての配列/リストのサイズがkであると仮定しましょう。次いで、HashMap<String, V>
及びHashMap<List<E>, V>
O(k)は複雑さを償却と同様に、O(なりますK + logN個 Java8で)最悪のケース。
* String
キーは不変であり、Javaは結果をhashCode()
プライベート変数hash
にキャッシュするため、キーの使用はより複雑なケースであり、一度しか計算されないことに注意してください。
/** Cache the hash code for the string */
private int hash; // Default to 0
ただし、JavaのString.hashCode()
実装がhash == 0
計算前にチェックを行っているため、上記のケースにも独自の最悪のケースがありhashCode
ます。しかし、ちょっと、hashcode
「f5a5a608」のようにゼロのaを出力する空でない文字列があります。ここを参照してください。この場合、メモ化は役に立たない可能性があります。