跳转至

集合操作的复杂度

set 类型是由唯一元素组成的无序集合。在 CPython 中它以哈希表实现,与字典类似。

复杂度参考

操作 时间 空间 备注
len() O(1) O(1) 直接计数
add(x) 平均 O(1),最坏 O(n) 均摊 O(1) 哈希冲突会导致 O(n)
remove(x) 平均 O(1),最坏 O(n) O(1) 哈希查找 + 删除
discard(x) 平均 O(1),最坏 O(n) O(1) 哈希查找 + 删除
pop() 平均 O(1) O(1) 移除任意一个元素
clear() O(n) O(1) 释放全部
x in set 平均 O(1),最坏 O(n) O(1) 哈希查找;冲突会导致 O(n)
copy() O(n) O(n) 浅拷贝
union(other) O(n+m) O(n+m) n、m = 集合大小
intersection(other) O(min(n,m)) O(min(n,m)) 遍历较小的集合
difference(other) O(n) O(n) n = 集合大小
symmetric_difference(other) O(n+m) O(n+m) 组合的集合操作
issubset() O(n) O(1) 检查所有元素
issuperset() O(m) O(1) m = 另一个集合的大小
isdisjoint() O(min(n,m)) O(1) 可提前终止
update(other) O(m) O(1) 原地并集;m = len(other)
difference_update(other) O(m) O(1) 原地差集
intersection_update(other) O(n) O(1) 原地交集;会重建集合
symmetric_difference_update(other) O(m) O(1) 原地对称差集

实现细节

哈希表实现

集合采用与字典相同的哈希表设计,但:

  • 只存储键(没有值)
  • 比字典更节省内存
  • 平均查找同样是 O(1)

集合运算

# Union: combines both sets
{1, 2} | {2, 3}  # {1, 2, 3} - O(len(s1) + len(s2))

# Intersection: common elements
{1, 2, 3} & {2, 3, 4}  # {2, 3} - O(min(len(s1), len(s2)))

# Difference: elements in first but not second
{1, 2, 3} - {2, 4}  # {1, 3} - O(len(s1))

# Symmetric difference: elements in either but not both
{1, 2} ^ {2, 3}  # {1, 3} - O(len(s1) + len(s2))

成员检测

# Very fast - O(1) hash lookup
s = {1, 2, 3, 4, 5}
if 3 in s:  # O(1), not O(n)
    pass

与列表的对比

# List membership: O(n) - must scan entire list
numbers_list = [1, 2, 3, 4, 5]
3 in numbers_list  # O(n)

# Set membership: O(1) - hash lookup
numbers_set = {1, 2, 3, 4, 5}
3 in numbers_set  # O(1) - much faster for large collections!

版本说明

  • 所有 Python 3 版本:核心复杂度未变
  • Python 3.9+:新增集合并集/交集运算符

各实现对比

CPython

标准哈希表实现。

PyPy

JIT 编译可能带来额外优化。

Jython

底层为 Java 的 HashSet,具有相同的 O(1) 特性。

最佳实践

推荐

  • 在大型集合上做成员检测时使用集合
  • 使用集合运算符(|&-^)来组合集合
  • 用集合去重:set(list_with_dups)
  • 需要可哈希的唯一元素时使用 frozenset

避免

  • 用列表做频繁的成员检测
  • 依赖集合的顺序(并无保证)
  • 在集合中放入不可哈希的类型(列表、字典)

常见用法

去重

# Bad: preserves list, but O(n²)
unique = []
for item in items:
    if item not in unique:
        unique.append(item)

# Good: O(n), but loses order
unique = list(set(items))

# Best: O(n) and preserves order (Python 3.7+)
unique = list(dict.fromkeys(items))

快速过滤

# Bad: O(n*m) - checks membership in list for each element
large_list = list(range(1000000))
exclusions = [1, 2, 3, ...]
filtered = [x for x in large_list if x not in exclusions]

# Good: O(n) - fast set lookup
exclusions_set = set(exclusions)
filtered = [x for x in large_list if x not in exclusions_set]

相关类型

延伸阅读