【发布时间】:2015-12-23 20:58:52
【问题描述】:
除了冲突检测和在哈希表中抛出 LinkedList 之外,还有哪些其他方式可以实现哈希表?碰撞检测是实现高效哈希表的唯一方法吗?
【问题讨论】:
标签: hashtable
除了冲突检测和在哈希表中抛出 LinkedList 之外,还有哪些其他方式可以实现哈希表?碰撞检测是实现高效哈希表的唯一方法吗?
【问题讨论】:
标签: hashtable
最终,一个有限大小的哈希表会发生冲突,至少任何通常编程的哈希表都会发生冲突。如果您的键是string 类型,那么哈希表有无限 个可能的键,但是使用哈希表,您只有有限数量的桶。因此,从根本上说,必须有碰撞。如果您要实现一个忽略冲突的哈希表,那么您将拥有一个非常奇怪的、不确定的数据结构,看起来会随机删除元素。
现在,后端使用的数据结构不必是链表。您可以将其实现为红黑树并从冲突中获得 log(n) 性能。您应该查看文章5 Myths About Hash Tables 和this Stack Overflow question about HashMaps vs Maps。
现在,如果您对密钥类型有所了解,假设密钥是一个 2 个字符长的字符串,那么可能的密钥数量就只有有限个,然后您可以继续创建一个“哈希”函数来转换密钥对于一个相对小的整数,您可以创建一个保证不会发生冲突的查找表。
需要注意的是,一个良好实现的哈希表不会受到太多冲突的影响。世界上存在比计算机每 5 天必须遍历链表中的三个节点一次更大的问题,例如世界饥饿(甚至如何实现高效的哈希函数)。
【讨论】:
vector,而 std::unordered_X 在重新哈希期间不会移动值)。
除了冲突检测和在哈希表中抛出 LinkedList 之外,还有哪些其他方式可以实现哈希表?
其他方式包括:
具有从元素发生碰撞的节点链接的另一种容器类型,例如平衡二叉树或向量/数组
GCC 的哈希表支持std::unordered_X 使用单个单链值列表,以及列表中的桶容器迭代器的连续数组;它有一些很棒的特性,包括优化迭代速度,不管当前的load_factor()
使用开放寻址/封闭散列,当插入/查找/擦除在它已散列到的存储桶中找到另一个键时,使用某种算法来查找另一个存储桶来代替(依此类推,直到它找到键、可以插入的已删除元素或未使用的存储桶);这种“探测”有多种选择,最简单的是尝试下一个桶的方法,另一种是二次 1、4、9、16...,另一种是使用替代散列函数。
完美的哈希函数(下)
冲突检测是实现高效哈希表的唯一方法吗?
【讨论】: