【发布时间】:2019-06-10 03:36:42
【问题描述】:
如何在 CPython 中实现frozenset 相等?特别是,我想知道 frozenset 中的各个元素如何相互比较以及它们的总时间复杂度。
我看了set and frozenset difference in implementation和https://stackoverflow.com/a/51778365/5792721。
第二个链接中的答案涵盖了比较集合中各个元素之前的步骤,但缺少实际的比较算法。
【问题讨论】:
如何在 CPython 中实现frozenset 相等?特别是,我想知道 frozenset 中的各个元素如何相互比较以及它们的总时间复杂度。
我看了set and frozenset difference in implementation和https://stackoverflow.com/a/51778365/5792721。
第二个链接中的答案涵盖了比较集合中各个元素之前的步骤,但缺少实际的比较算法。
【问题讨论】:
可以在here 找到相关实现。假设我们要检查两个 sets v 和 w 是否相等,算法是这样的:
false。 这引用了PySetObject的size属性,所以它是一个常数时间的操作。
sets 是否都是frozensets。如果是这样,并且它们的哈希值不同,则返回 false。同样,这引用了PySetObject 的hash 属性,这是一个常数时间操作。这是可能的,因为frozensets 是不可变对象,因此在创建它们时会计算它们的哈希值。
w 是否是v 的子集。这是通过遍历v 的每个元素并检查它是否存在于w 中来完成的。
迭代必须在整个v 上执行,因此在最坏的情况下它的大小是线性的(如果在最后一个位置找到不同的元素)。
sets 的成员资格测试通常在平均情况下需要恒定时间,在最坏情况下需要线性时间;将两者结合起来,在平均情况下,时间与 v 的大小呈线性关系,在最坏情况下,时间与 len(v) * len(w) 成正比。
从某种意义上说,这是最坏情况的平均情况,因为它假定前两次检查总是返回true。如果您的数据很少倾向于具有相同大小的sets,它们也具有相同的哈希值但包含不同的对象,那么在平均情况下,比较仍将在恒定时间内运行。
【讨论】:
set 和 frozenset 都使用 the set_richcompare() function 进行相等测试。这里没有区别。
set_richcompare(),正如其他答案所提到的,比较大小然后散列。然后,它checks whether one is a subset of the other,它只是遍历集合 1 中的每个元素,并检查它是否在集合 2 中。这个检查在其他方面与 checking whether an element is in a set 相同。这是通过哈希表查找完成的,对具有相同哈希值的项目进行线性搜索。存在性检查的复杂度为O(1) amortized or O(len(s)) worst-case,因此set_issubset() 的检查复杂度为 O(len(s1)) 摊销,或 O(len(s1)*len(s2)) 最坏情况。
【讨论】: