什么时候使用哈希表?

When to use hash tables?

在什么情况下使用哈希 table 可以提高性能,什么情况下不能?什么情况下使用散列 table 不适用?

我们使用哈希表来获取 O(1) 的访问时间。想象一下字典。当您正在寻找一个词时,例如“happy”,您会直接跳到 'H'。这里的哈希函数由起始字母表决定。然后你在 H 桶中寻找快乐(实际上是 H 桶,然后是 HA 桶,然后是 HAP 桶,等等)。

当您的数据已排序或需要像已排序的数字一样排序时,使用哈希表没有意义。 (字母顺序为 ABCD....XYZ,但如果您切换 A 和 Z 并不重要,只要您知道它已在您的字典中切换。)

What are the cases when using hash table can improve performance, and when it does not?

如果您有理由关心,请使用散列 tables 和您正在考虑的任何其他内容来实施,将您的实际数据放在一起,并衡量哪个表现更好。

也就是说,如果散列 tables 具有您需要的操作(即您不希望按排序顺序迭代它,或将它快速与另一个散列 table 进行比较),并且有数百万或更多(数十亿,万亿...)元素,那么它可能是您的最佳选择,但很大程度上取决于哈希 table 实现(尤其是封闭哈希与开放哈希的选择) ,对象大小,哈希函数质量和计算成本/运行时间),比较成本,计算机在不同缓存级别的内存性能的奇怪之处......简而言之:太多的事情使得即使是有根据的猜测也比测量更好的选择,当它很重要。

and what are the cases when using hash tables are not applicable?

主要是在:

  • 无法对输入进行哈希处理(例如,你得到了二进制 blob,不知道其中哪些位是重要的,但你确实有一个 int cmp(const T&, const T&) 函数,你可以用于 std::map) 或

  • available/possible 哈希函数很容易发生冲突,或者

  • 您想避免最坏情况下的性能命中:

    • 处理大量散列冲突元素(可能 "engineered" 是有人试图让您的软件崩溃或减慢速度)

    • 调整散列的大小table:除非预先设置得足够大(当使用过多的内存时这可能是浪费和缓慢的),大多数实现将超出他们正在使用的数组对于散列 table 时不时地,然后分配一个更大的数组并复制内容:这可以使导致此重新散列的特定插入比正常的 O(1) 行为慢得多,即使平均仍然是 O(1);如果您在所有情况下都需要更一致的行为,可以使用平衡二叉树之类的东西

  • 您的访问模式非常专业(例如,经常对具有某些特定排序顺序的 "nearby" 键的元素进行操作),因此缓存效率对于其他存储模型来说更好它们在内存中附近(例如桶排序元素),即使您并不完全依赖排序顺序,例如迭代