【问题标题】:Hash Table Implementation - alternatives to collision detection哈希表实现 - 碰撞检测的替代方案
【发布时间】:2015-12-23 20:58:52
【问题描述】:

除了冲突检测和在哈希表中抛出 LinkedList 之外,还有哪些其他方式可以实现哈希表?碰撞检测是实现高效哈希表的唯一方法吗?

【问题讨论】:

    标签: hashtable


    【解决方案1】:

    最终,一个有限大小的哈希表会发生冲突,至少任何通常编程的哈希表都会发生冲突。如果您的键是string 类型,那么哈希表有无限 个可能的键,但是使用哈希表,您只有有限数量的桶。因此,从根本上说,必须有碰撞。如果您要实现一个忽略冲突的哈希表,那么您将拥有一个非常奇怪的、不确定的数据结构,看起来会随机删除元素。

    现在,后端使用的数据结构不必是链表。您可以将其实现为红黑树并从冲突中获得 log(n) 性能。您应该查看文章5 Myths About Hash Tablesthis Stack Overflow question about HashMaps vs Maps

    现在,如果您对密钥类型有所了解,假设密钥是一个 2 个字符长的字符串,那么可能的密钥数量就只有有限个,然后您可以继续创建一个“哈希”函数来转换密钥对于一个相对小的整数,您可以创建一个保证不会发生冲突的查找表。

    需要注意的是,一个良好实现的哈希表不会受到太多冲突的影响。世界上存在比计算机每 5 天必须遍历链表中的三个节点一次更大的问题,例如世界饥饿(甚至如何实现高效的哈希函数)。

    【讨论】:

    • 您也可以使用探测,它(虽然仍然是一种处理冲突的方法)不需要任何其他结构来实现存储桶(因为每个存储桶将只存储一个项目)。自然,每次空间不足时,您都必须调整哈希图的大小。
    • 是的,我忘了探测大声笑。我想我记得我的数据结构教授提出了这个策略,因为它并不比链表快,而且填满哈希表的速度也更快。 (我猜这对内存复杂性更好)
    • 哦,当然。探测根本没有效率(它具有线性查找时间和条目数量的固定限制),但它确实满足了“不使用链表的哈希表的替代实现”要求。 :P
    • @cypher: 不是这样...探测可能非常有效:尤其是对于可以直接放入表中的小值,以及与指针表相比时(在) 对于链表,插入和搜索通常快一个数量级。它的重要问题包括删除,这很难在 O(1)-ish 时间内执行而不允许所有未来操作的性能下降,以及重新散列以增加容量,这本质上必须移动所有值(就像一个vector,而 std::unordered_X 在重新哈希期间不会移动值)。
    【解决方案2】:

    除了冲突检测和在哈希表中抛出 LinkedList 之外,还有哪些其他方式可以实现哈希表?

    其他方式包括:

    • 具有从元素发生碰撞的节点链接的另一种容器类型,例如平衡二叉树或向量/数组

    • GCC 的哈希表支持std::unordered_X 使用单个单链值列表,以及列表中的桶容器迭代器的连续数组;它有一些很棒的特性,包括优化迭代速度,不管当前的load_factor()

    • 使用开放寻址/封闭散列,当插入/查找/擦除在它已散列到的存储桶中找到另一个键时,使用某种算法来查找另一个存储桶来代替(依此类推,直到它找到键、可以插入的已删除元素或未使用的存储桶);这种“探测”有多种选择,最简单的是尝试下一个桶的方法,另一种是二次 1、4、9、16...,另一种是使用替代散列函数。

    • 完美的哈希函数(下)

    冲突检测是实现高效哈希表的唯一方法吗?

    • 有时可以找到不会发生冲突的perfect hash function,但这通常只适用于非常有限的输入集,无论是由于输入的性质(例如,活人的出生月份和年份只有一千个可能的值),或者因为在编译时知道一小部分(例如,编译器的一组 200 个关键字)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-30
      • 1970-01-01
      • 1970-01-01
      • 2012-06-01
      • 2010-11-16
      • 1970-01-01
      相关资源
      最近更新 更多