別々に格納された値への32ビットキーと32ビットポインタを持つハッシュテーブルのサイズはどれくらいですか?
2 ^ 32スロット*(4バイト(キー)+ 4バイト(値へのポインター))= 4 * 10 ^ 9 *(4 + 4)= 32GBになりますか?
ハッシュテーブルのスペースの複雑さを理解しようとしています。
ハッシュテーブルがハッシュ関数の値とスロットに一致しません。ハッシュ関数は、ハッシュ関数の範囲よりもはるかに小さい参照ベクトルのサイズを法として計算されます。この値は固定されているため、スペースの複雑さの計算では考慮されません。
したがって、すべての妥当なハッシュテーブルのスペースの複雑さはO(n)です。
一般的に、これは非常にうまくいきます。キースペースは大きい場合がありますが、格納する値の数は通常、非常に簡単に予測できます。確かに、データ構造のオーバーヘッドに対して機能的に許容できるメモリの量は、通常は明らかです。
これが、ハッシュテーブルが非常に普及している理由です。多くの場合、特定のタスクに最適なデータ構造を提供し、厳密に制限されたメモリオーバーヘッドとログよりも優れたメモリを組み合わせます。2n時間計算量。私は二分木が大好きですが、通常はハッシュテーブルに勝るものはありません。
あなたは間違った質問をしていると思います。データ構造のスペースの複雑さは、データ構造が保持する要素の量に関連して、データ構造が占めるスペースの量を示します。たとえば、O(1)
のスペースの複雑さは、そこに要素をいくつ入れても、データ構造が常に一定のスペースを消費することを意味します。 O(n)
は、スペース消費がその中の要素の量に比例して増加することを意味します。
ハッシュテーブルは通常、O(n)
のスペースの複雑さを持っています。
だからあなたの質問に答えるために:それはそれが現在保存している要素の数に依存し、現実の世界では実際の実装にも依存します。
ハッシュテーブルのメモリ消費量の下限は次のとおりです:(格納する値の数)*(SizeOf a Value)。したがって、ハッシュテーブルに100万個の値を格納し、それぞれが4バイトを占める場合、少なくとも400万バイト(約4MB)を消費します。通常、実際の実装ではインフラストラクチャにもう少しメモリを使用しますが、これも実際の実装に大きく依存し、確実に見つける方法はなく、測定するしかありません。
バケットの数が要素のサイズの2倍に等しい単純なハッシュテーブルがあるとしましょう。つまり、O(2n) O(n)である要素の数です。
要素の数が使用可能なバケットの数の半分を超える場合は、バケットの新しい配列を作成し、サイズを2倍にして、すべての要素を新しいバケットの配列内の新しい場所に再ハッシュする必要があります。
386 public V put(K key, V value) {
387 if (key == null)
388 return putForNullKey(value);
389 int hash = hash(key.hashCode());
390 int i = indexFor(hash, table.length);
391 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
392 Object k;
393 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
394 V oldValue = e.value;
395 e.value = value;
396 e.recordAccess(this);
397 return oldValue;
398 }
399 }
401 modCount++;
402 addEntry(hash, key, value, i);
403 return null;
404 }
768 void addEntry(int hash, K key, V value, int bucketIndex) {
769 Entry<K,V> e = table[bucketIndex];
770 table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
771 if (size++ >= threshold)
772 resize(2 * table.length);
773 }
471 void resize(int newCapacity) {
472 Entry[] oldTable = table;
473 int oldCapacity = oldTable.length;
474 if (oldCapacity == MAXIMUM_CAPACITY) {
475 threshold = Integer.MAX_VALUE;
476 return;
477 }
479 Entry[] newTable = new Entry[newCapacity];
480 transfer(newTable);
481 table = newTable;
482 threshold = (int)(newCapacity * loadFactor);
483 }
488 void transfer(Entry[] newTable) {
489 Entry[] src = table;
490 int newCapacity = newTable.length;
491 for (int j = 0; j < src.length; j++) {
492 Entry<K,V> e = src[j];
493 if (e != null) {
494 src[j] = null;
495 do {
496 Entry<K,V> next = e.next;
497 int i = indexFor(e.hash, newCapacity);
498 e.next = newTable[i];
499 newTable[i] = e;
500 e = next;
501 } while (e != null);
502 }
503 }
504 }
参照:
それでも、この質問に対する完全な答えはありません。占有スペースがわかりません。問題の私の理解によると。サイズは動的であり、入力のサイズによって異なります。
つまり、ハッシュ関数の値と比較して非常に小さい乱数、ハッシュテーブルサイズから始めます。次に、入力を挿入します。ここで、衝突が発生し始めると、ハッシュテーブルのサイズが動的に2倍になります。これが、O(n)複雑さの理由だと思います。間違っている場合は、訂正してください。