Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么使用哈希而不是测试真正的相等性?_Python_Dictionary_Hash - Fatal编程技术网

Python 为什么使用哈希而不是测试真正的相等性?

Python 为什么使用哈希而不是测试真正的相等性?,python,dictionary,hash,Python,Dictionary,Hash,我最近一直在研究Python的字典(我相信它们在其他语言中被称为关联数组),但对其键的一些限制感到困惑 首先,dict键必须是不可变的。当我查看其背后的逻辑时,答案是字典就像哈希表一样查找键的值,因此不可变键(如果它们可以哈希)可能会更改其哈希值,从而在检索值时造成问题 我很好地理解了为什么会这样,但我仍然有点困惑于使用哈希表的意义。如果您只是没有散列键并测试真正的相等性(假设以相同方式构造的对象比较相等),那么您可以通过使用两个列表复制字典的大部分功能,而不受此限制 所以,我想这才是我真正的问

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

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

我很好地理解了为什么会这样,但我仍然有点困惑于使用哈希表的意义。如果您只是没有散列键并测试真正的相等性(假设以相同方式构造的对象比较相等),那么您可以通过使用两个列表复制字典的大部分功能,而不受此限制

所以,我想这才是我真正的问题——使用散列而不是相等查找值背后的原理是什么


如果非要我猜的话,很可能是因为比较整数的速度非常快,而且经过了优化,而比较其他类的实例的速度可能不快。

您似乎忽略了哈希表的整个要点,它是快速(O(1))1检索的,没有哈希就无法实现,即,将键转换为某种分布均匀的整数,用作表的索引。请注意,在检索时仍然需要相等,以便能够处理哈希冲突2,但只有当您已经将元素集缩小到具有特定哈希的元素时,才能使用相等

只要相等,您就可以用并行数组或类似的东西复制类似的功能,但这将使检索成为O(n)3;如果您要求严格的弱排序,那么您可以实现RB树,它允许O(logn)检索。但是O(1)需要散列

请看一看,了解有关哈希表的更多信息


注释

  • 在病态场景中(所有元素都放在同一个桶中),它可能变成O(n),但如果使用好的散列函数,这是不应该发生的
  • 由于不同的元素可能具有相同的散列,在到达与散列对应的bucket之后,必须检查是否实际检索与给定键关联的元素
  • 或者O(logn),如果您保持数组排序,但这会使插入复杂化,由于元素的移动,插入变得平均O(n);但是再一次,如果你有顺序,你可能想要一个RB树或堆

  • 通过使用hastables,您可以获得
    O(1)
    检索数据,而与每个独立值进行相等性比较时,将获得
    O(n)
    (在顺序搜索中)或
    O(log(n))
    (在二进制搜索中)


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

    @FrédéricHamidi O(n log n)??你怎么知道的?即使对于R/B树,项访问也只是O(logn),如果它的时间复杂度为O(nlogn)@JoeC,那么使用哈希映射有什么意义呢,从内存:)我可能错了,我正在四处搜索以进行双重检查。我的坏,我能找到的最坏的情况是O(logn/logn)。我的观点是正确的。@FrédéricHamidi同样,O(n)比O(n log n)=>从你所说的列表比哈希表快:)@JoeC,是的,你是对的,我想知道我从哪里得到这种复杂性。看起来我把排序的复杂性搞混了。。。无论如何,现在我不会再犯同样的错误了:)@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表示法忽略常数因子。