web-dev-qa-db-ja.com

ハッシュテーブルのスペースの複雑さはどれくらいですか?

別々に格納された値への32ビットキーと32ビットポインタを持つハッシュテーブルのサイズはどれくらいですか?

2 ^ 32スロット*(4バイト(キー)+ 4バイト(値へのポインター))= 4 * 10 ^ 9 *(4 + 4)= 32GBになりますか?

ハッシュテーブルのスペースの複雑さを理解しようとしています。

ハッシュテーブルがハッシュ関数の値とスロットに一致しません。ハッシュ関数は、ハッシュ関数の範囲よりもはるかに小さい参照ベクトルのサイズを法として計算されます。この値は固定されているため、スペースの複雑さの計算では考慮されません。

したがって、すべての妥当なハッシュテーブルのスペースの複雑さはO(n)です。

一般的に、これは非常にうまくいきます。キースペースは大きい場合がありますが、格納する値の数は通常、非常に簡単に予測できます。確かに、データ構造のオーバーヘッドに対して機能的に許容できるメモリの量は、通常は明らかです。

これが、ハッシュテーブルが非常に普及している理由です。多くの場合、特定のタスクに最適なデータ構造を提供し、厳密に制限されたメモリオーバーヘッドとログよりも優れたメモリを組み合わせます。2n時間計算量。私は二分木が大好きですが、通常はハッシュテーブルに勝るものはありません。

9
DigitalRoss

あなたは間違った質問をしていると思います。データ構造のスペースの複雑さは、データ構造が保持する要素の量に関連して、データ構造が占めるスペースの量を示します。たとえば、O(1)のスペースの複雑さは、そこに要素をいくつ入れても、データ構造が常に一定のスペースを消費することを意味します。 O(n)は、スペース消費がその中の要素の量に比例して増加することを意味します。

ハッシュテーブルは通常、O(n)のスペースの複雑さを持っています。

だからあなたの質問に答えるために:それはそれが現在保存している要素の数に依存し、現実の世界では実際の実装にも依存します。

ハッシュテーブルのメモリ消費量の下限は次のとおりです:(格納する値の数)*(SizeOf a Value)。したがって、ハッシュテーブルに100万個の値を格納し、それぞれが4バイトを占める場合、少なくとも400万バイト(約4MB)を消費します。通常、実際の実装ではインフラストラクチャにもう少しメモリを使用しますが、これも実際の実装に大きく依存し、確実に見つける方法はなく、測定するしかありません。

12
ChrisWue

バケットの数が要素のサイズの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  }

参照:

HashMap.put
http://grepcode.com/file/repository.grepcode.com/Java/root/jdk/openjdk/6-b14/Java/util/HashMap.Java#HashMap.put%28Java .lang.Object%2Cjava.lang.Object%29

1
joseph

それでも、この質問に対する完全な答えはありません。占有スペースがわかりません。問題の私の理解によると。サイズは動的であり、入力のサイズによって異なります。

つまり、ハッシュ関数の値と比較して非常に小さい乱数、ハッシュテーブルサイズから始めます。次に、入力を挿入します。ここで、衝突が発生し始めると、ハッシュテーブルのサイズが動的に2倍になります。これが、O(n)複雑さの理由だと思います。間違っている場合は、訂正してください。

0
Anshu Kandhari