具有32位密钥的哈希表的大小和单独存储的值的32位指针是什么?
它是2 ^ 32个插槽*(4个字节(键)+ 4个字节(指向值的指针)) = 4 * 10 ^ 9 *(4 + 4)= 32GB?
我试图理解哈希表的空间复杂性。
答案 0 :(得分:11)
我认为你问的是错误的问题。数据结构的空间复杂性表明它占据的空间相对于它所拥有的元素数量。例如,空间复杂度O(1)
意味着无论您放入多少元素,数据结构都会消耗恒定的空间。 O(n)
意味着空间消耗随着其中元素的数量线性增长。
散列表的空间复杂度通常为O(n)
。
所以回答你的问题:这取决于它当前存储的元素数量,以及现实世界中实际实现的元素数量。
哈希表的内存消耗的下限是:(要存储的值的数量)*(SizeOf a Value)。因此,如果您想在哈希表中存储100万个值,每个值占用4个字节,那么它将消耗至少400万个字节(大约4MB)。通常,现实世界的实现会为基础设施使用更多的内存,但又一次:这在很大程度上取决于实际的实现,并且没有办法确定但是要测量它。
答案 1 :(得分:8)
散列表与散列函数值和插槽不匹配。以比散列函数范围小得多的参考向量的大小为模计算散列函数。因为这个值是固定的,所以在空间复杂度计算中不予考虑。
因此,每个合理哈希表的空间复杂度为 O(n)。
总的来说,这很好。虽然密钥空间可能很大,但存储的值的数量通常很容易预测。当然,功能上可接受的数据结构开销的内存量通常是显而易见的。
这就是哈希表无处不在的原因。它们通常为给定任务提供最佳数据结构,混合严格限制的内存开销,优于log 2 n 时间复杂度。我喜欢二叉树,但它们通常不会打哈希表。
答案 2 :(得分:1)
让我们假设我们有一个天真的哈希表,其中桶的数量等于元素大小的两倍。即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 }
参考文献:
答案 3 :(得分:0)
这个问题还没有完美的答案。我不确定占用的空间。 根据我对这个问题的理解。大小是动态的,并随输入的大小而变化。
那就是我们从一个随机数,哈希表大小开始,与哈希函数值相比,这个数字非常少。然后我们插入输入。现在,随着冲突的开始,我们动态地将哈希表大小加倍。 我认为这就是O(n)复杂性的原因。如果我错了,请纠正我。