【问题标题】:Why use hashes instead of test true equality?为什么使用哈希而不是测试真正的相等性?
【发布时间】:2013-11-28 14:42:25
【问题描述】:

我最近一直在研究 Python 的字典(我相信它们在其他语言中被称为关联数组)并且对其键的一些限制感到困惑。

首先,dict 键必须是不可变的。当我查看它背后的逻辑时,答案是字典像哈希表一样工作来查找键的值,因此不可变键(如果它们是可哈希的)可能会改变它们的哈希值,从而在检索值时导致问题.

我明白为什么会这样,但我仍然对使用哈希表的意义感到有些困惑。如果您只是不散列键并测试真正的相等性(假设相同构造的对象比较相等),则只需使用两个列表即可复制字典的大部分功能而不受此限制。

所以,我想这是我真正的问题 - 使用哈希而不是相等来查找值的基本原理是什么?

如果我不得不猜测,这可能仅仅是因为比较整数非常快且经过优化,而比较其他类的实例可能不是。

【问题讨论】:

  • @FrédéricHamidi O(n log n)??你是怎么知道的?即使对于 R/B 树,项目访问也只有 O(log n),如果它的时间复杂度为 O(n log n),那么使用 hash map 有什么意义
  • @JoeC,凭记忆 :) 我在这里可能错了,我正在四处寻找以仔细检查。 我的错,我能找到的最坏情况是 O(log n / log log n)。我的立场是正确的。
  • @FrédéricHamidi 同样,O(n) 比 O(n log n) 好 => 从你所说的来看,列表比哈希表更快:)
  • @JoeC,是的,你是对的,我想知道我是从哪里得到这种复杂性的。看起来我对排序复杂性感到困惑......无论如何,现在我不会再犯同样的错误了:)

标签: python dictionary hash


【解决方案1】:

您似乎错过了哈希表的全部要点,它是快速 (O(1))1 检索,并且如果没有哈希就无法实现,即将键转换为一些一种分布良好的整数,用作表的索引。请注意,检索时仍然需要相等性才能处理散列冲突2,但只有在您已经将元素集缩小到具有特定散列的元素集时才使用它。

仅通过相等,您可以使用并行数组或类似的东西复制类似的功能,但这会使检索 O(n)3;如果你要求严格的弱排序,你可以实现 RB 树,它允许 O(log n) 检索。但是 O(1) 需要散列。

查看Wikipedia,了解有关哈希表的更多信息。


注意事项

  1. 在不正常的情况下(所有元素都放在同一个桶中)可能会变成 O(n),但这不应该发生在良好的散列函数中。
  2. 由于不同的元素可能具有相同的哈希值,因此在到达与哈希值对应的存储桶后,您必须检查您是否真的在检索与给定键关联的元素。
  3. 或者 O(log n),如果你保持你的数组排序,但这会使插入变得复杂,由于移动元素,平均变成 O(n);但话又说回来,如果您有订单,您可能需要一个 RB 树或一个堆。

【讨论】:

  • @FrédéricHamidi:或多或少;在某些病态情况下,您可能会达到 O(n)(所有元素都获得相同的哈希),但这就像快速排序的最坏情况 - 在实践中预计不会发生。
  • RB检索是O(log(n))而不是O(n*log(n)) ....否则会比线性搜索差。
  • 即使发生碰撞也是 O(1) 平均值。也就是说,使用分布良好的散列,每次访问都会得到一些平均冲突数,比如 1。有时会发生 1 次冲突,有时会发生 2 次,有时会发生 0 次,有时甚至会发生 5 次,但很少见。因此,平均而言,您需要 2 次尝试访问任何内容(1 次冲突,1 次重试)。它是 O(2)。 O(2) 与 O(1) 相同:O 表示法忽略常数因子。
【解决方案2】:

通过使用 hastables,您可以获得 O(1) 检索数据,而与每个独立值比较是否相等将采用 O(n)(在顺序搜索中)或 O(log(n)) 在二分搜索中。

还要注意O(1) 是摊销时间,因为如果有多个值散列到同一个键,则需要在这些值中进行顺序搜索。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多