web-dev-qa-db-ja.com

HashMapはなぜ初期容量が2の累乗である必要があるのですか?

私は次のことを見て、JavaのHashMapソースコードを調べていました。

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

私の質問は、なぜ最初にこの要件が存在するのですか?また、カスタム容量でHashMapを作成できるコンストラクターは、2の累乗に変換します。

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

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

また、自動リハッシュが実行されると、正確にはどうなりますか?ハッシュ関数も変更されていますか?

41
Sushant

マップは、任意のint値(負の場合もある)を[0, table.length)。いつ table.lengthは2のべき乗であり、実行できますreally安く、そしてindexForで:

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

テーブルの長さが異なる場合、余りを計算し、それが負でないことを確認する必要があります。これは間違いなくマイクロ最適化ですが、おそらく有効なものです:)

また、自動リハッシュが実行されると、正確にはどうなりますか?ハッシュ関数も変更されていますか?

どういう意味かよくわからない。同じハッシュコードが使用されます(各キーでhashCodeを呼び出すことによって計算されるため)。ただし、テーブルの長さが変更されるため、テーブル内での分布は異なります。たとえば、テーブルの長さが16の場合、ハッシュコード5と21の両方がテーブルエントリ5に格納されます。テーブルの長さが32に増えると、それらは異なるエントリになります。

44
Jon Skeet

理想的な状況は、実際にHashMapのバッキング配列に素数サイズを使用することです。そうすることで、キーがアレイ全体に自然に分散されます。ただし、これはmod分割で機能し、その操作はJavaのすべてのリリースで次第に遅くなりました。ある意味では、2のべき乗のアプローチは、ハッシュコードの実装が適切でないと、配列にキーの衝突が発生する可能性が高くなるため、想像できる最悪のテーブルサイズです。

そのため、JavaのHashMap実装には、貧弱なハッシュコードを補正するhash(int)である別の非常に重要なメソッドがあります。

5
M Platvoet