2011-12-02 7 views
30

私は、次のなぜHashMapは初期容量が2の累乗であることを要求しますか?

//The default initial capacity - MUST be a power of two. 
static final int DEFAULT_INITIAL_CAPACITY = 16; 

私の質問を見たとき、私はJavaのHashMapのソースコードを経由して、この要件は、最初の場所に存在しない理由は?私はまた、カスタム容量のHashMapを作成することができますコンストラクタは2の累乗に変換することを参照してください。

int capacity = 1; 
while (capacity < initialCapacity) 
    capacity <<= 1; 

容量は常に2の累乗でなければならないのはなぜ?

また、自動再ハッシングを実行すると、どういうことが起こりますか?ハッシュ関数も変更されていますか?

答えて

38

マップは、intの値(負の場合があります)を[0, table.length)の値にマッピングして、任意のキーに使用する内部テーブルインデックスを使用する必要があります。 table.lengthが安く本当にを行うことができ、2のべき乗、あるとき - とindexForで、次のとおりです。

static int indexFor(int h, int length) { 
    return h & (length-1); 
} 

異なるテーブル長を使用すると、残りの部分を計算し、それが非だことを確認する必要があると思います否定的。これは間違いなくマイクロ最適化ですが、おそらく有効なものです。

また、自動再ハッシングを実行すると、どういうことが起こりますか?ハッシュ関数も変更されていますか?

あなたが何を意味するのかは私には明らかではありません。同じハッシュコードが使用されます(各キーでhashCodeを呼び出して計算されるため)が、テーブルの長さが変更されるため、テーブル内で異なるハッシュコードが配布されます。たとえば、テーブルの長さが16の場合、ハッシュコード5と21の両方がテーブルエントリ5に格納されます。テーブルの長さが32に増加すると、異なるエントリになります。

+0

まさに私が探していたものです、ありがとうございます。 もう1つの疑問は、すべてのデータを保持しているのに、Entryテーブルが一時的に一時停止していることです。 – Sushant

+1

@Sushant:テーブル内のデータはwriteObject内で*明示的に*シリアル化されているため、すべての空のエントリは書き出されません。フィールドを一時的にすると、通常のシリアライゼーションコードは 'defaultWriteObject'の呼び出しで*書かれて*書き出されなくなります。 –

+0

@JonSkeet h&(length-1)はどのようにネガを扱うのですか?長さ= 16とh = -7と言うことができます – Geek

2

実際には、HashMapのバッキングアレイに素数サイズを使用するのが理想的です。そうすれば、キーはアレイ全体に自然に分散されます。しかし、これはmod分割で動作し、その操作はJavaのすべてのリリースで遅くなり、遅くなりました。 ある意味では、2つの手法の威力は、貧弱なハッシュコード実装では配列内でキー衝突を起こしやすいため、想像できる最悪のテーブルサイズです。

そのため、JavaのHashMap実装ではもう1つの非常に重要なメソッドが見つかるでしょう。これはhash(int)であり、貧弱なハッシュコードを補うものです。

+0

はい、多くの意味がありますが、ハッシュ(int)関数が元のハッシュコードをどのように改善するかについてさらに詳しくお話できます。私はそれが数ビットのxorを取るのを見ますが、私はそれを完全に理解していません。 – Sushant

+1

基本的に、2の累乗法を使うと、hashCodeの下位ビットを重要なものにします。貧弱なhashCode実装では、これはあまり違いはありません(例:10110111と00000111)。だから、ビットのすべてのシフトでは、より高いものがより重要になります。 –

+0

hmm私は見ています..thanks – Sushant

関連する問題