【问题标题】:What is the space complexity of a hash table?哈希表的空间复杂度是多少?
【发布时间】:2011-09-25 16:13:54
【问题描述】:

具有 32 位键和 32 位指针的哈希表的大小分别存储是多少?

是否会是 2^32 个插槽 * (4 Bytes (key) + 4 Bytes (pointers to values)) = 4 * 10^9 * (4 + 4) = 32GB ?

我正在尝试了解哈希表的空间复杂度。

【问题讨论】:

  • 这取决于哈希表。没有固定的答案,除非您已经知道它是如何工作的(在这种情况下,您已经知道答案)。

标签: hashmap hashtable hash


【解决方案1】:

我认为你问错了问题。数据结构的空间复杂度表示它占用的空间相对于它所拥有的元素数量。例如,O(1) 的空间复杂度意味着无论您在其中放入多少元素,数据结构总是消耗恒定的空间。 O(n) 意味着空间消耗随着其中元素的数量线性增长。

哈希表的空间复杂度通常为O(n)

所以回答你的问题:这取决于它当前存储的元素数量,在现实世界中还取决于实际实现。

哈希表内存消耗的下限是:(要存储的值的数量)*(值的大小)。因此,如果您想在哈希表中存储 100 万个值并且每个值占用 4 个字节,那么它将消耗至少 400 万个字节(大约 4MB)。通常,现实世界的实现会为基础架构使用更多内存,但同样:这在很大程度上取决于实际的实现,除了测量之外没有办法确定。

【讨论】:

  • 但是如果我必须估计一个哈希表将占用多少空间..给定产生 32 位键的哈希函数..并且考虑到我正在存储指向存储在其他地方的值的指针我可以在哪里做?
  • 谢谢,真的很感激......我还是有点困惑......我在其他答案中添加了评论。
【解决方案2】:

哈希表与哈希函数值和槽不匹配。散列函数是根据比散列函数范围小得多的参考向量的大小来计算的。因为这个值是固定的,所以在空间复杂度计算中不考虑。

因此,每一个合理的哈希表的空间复杂度都是O(n)。

总的来说,这很有效。虽然键空间可能很大,但要存储的值的数量通常很容易预测。当然,数据结构开销在功能上可接受的内存量通常是显而易见的。

这就是哈希表如此普遍的原因。它们通常为给定任务提供最佳数据结构,将严格限制的内存开销与优于 log2n 的时间复杂度混合在一起。我喜欢二叉树,但它们通常不会胜过哈希表。

【讨论】:

  • 假设我有一个哈希表,当我创建它时,我不知道我将在其中存储多少元素..所以我没有指定容量。我猜它采用的默认加载工厂是 0.75。现在我散列我的第一个值,它是一个字符串 S,h(S) 产生了一个键 4294967294。我将这个键和一个 4 字节指针存储在我的散列表中。在这一点上..有什么方法可以估计它占用了多少内存?根据空间复杂度 O(n),它应该只占用 4Byte Key + 4 Byte value + 对象本身的一些开销(标题、填充等)。不会发生 2^32 个插槽的预分配..对吗?
  • 是的。典型的 HT 可能以包含 100 个(nil)指针的数组开始,安装的第一个值将指向您描述的对象。
  • 有什么方法可以计算产生哈希通常需要多长时间? (以 1 PB 数据为例)
  • @Arash 不,没有。这在很大程度上取决于使用的哈希函数、可用的 CPU 功率和 I/O 带宽。
【解决方案3】:

假设我们有一个简单的哈希表,其中桶的数量等于元素大小的两倍。也就是 O(2n) 的元素个数,也就是 O(n)。

当元素数量超过可用桶数的一半时,您需要创建一个新的桶数组,将大小翻倍并将所有元素重新散列到新桶数组中的新位置。

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

Grepcode 已关闭,您可以在此处查看 openjdk 存储库作为更好的参考: http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/HashMap.java

【讨论】:

    【解决方案4】:

    这个问题仍然没有完美的答案。我不确定占用的空间。 根据我对这个问题的理解。大小是动态的,随输入的大小而变化。

    也就是说,我们从一个随机数开始,哈希表大小,与哈希函数值相比非常小。然后我们插入输入。现在,随着冲突开始发生,我们动态地将哈希表大小加倍。 我认为这就是 O(n) 复杂度的原因。如果我错了,请纠正我。

    【讨论】:

    • 这是答案还是问题?
    猜你喜欢
    • 2014-08-06
    • 1970-01-01
    • 2019-09-12
    • 1970-01-01
    • 2016-11-03
    • 2020-11-19
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多