python中集合(set)原理及其操作

原理

Python 中的集合(set)是一个无序的不重复元素序列。它们可以用来进行成员测试、去除重复项以及数学上的集合操作,如并集、交集、差集和对称差分。

Python 中的集合(set)是基于哈希表实现的。了解集合的原理,首先需要理解哈希表(Hash Table)的概念。

哈希表

哈希表是一种使用哈希函数组织数据,以支持快速插入和搜索的数据结构。它通过将键值对映射到表中一个位置来访问记录,以加快查找速度。这个映射函数称为哈希函数,存放记录的数组称为哈希表或散列表。

集合工作原理

当你向集合添加一个元素时,Python 会首先计算该元素的哈希值(hash value),这个值决定了该元素在内部数据结构中的存储位置。如果两个不同元素具有相同的哈希值,则会发生冲突;Python 内部通过开放寻址法或链地址法等方式来解决这种冲突。

  1. 无序性:由于集合中元素位置是根据其哈希值确定,并不依赖于插入顺序,因此 Python 中集合是无序的。
  2. 唯一性:在任何时候,每个元素都有唯一确定的哈希值(即使存在冲突),所以集合中不会有重复元素。
  3. 高效性:由于基于哈希实现,大多数情况下(假设没有太多冲突),集合操作如添加、检查成员资格、删除等操作可以接近 O(1) 的时间复杂度完成。

动态调整大小

随着向集合添加更多元素,其内部结构可能变得过满(即装载因子过高)。为了保持操作效率,在达到某个阈值时,Python 会自动增加存储空间,并重新计算所有已存储对象的位置。这个过程称为“重新散列”或“扩容”,虽然它可能导致单次操作时间较长但确保整体上操作效率。

示例说明

考虑以下简单示例:

my_set = set()
print(my_set)

# 添加几个不同类型对象
my_set.add(42)
my_set.add("hello")
my_set.add((1, 2, 3))

print(my_set)
  • 当我们逐一添加 42"hello"(1, 2, 3)my_set 集合时:
    • 对每一个对象调用 hash() 函数获取其 hash 值。
    • 使用 hash 值找到在内部数据结构中应该存储该对象信息的位置并保存。
  • 尽管 (1, 2, 3) 是可迭代类型且包含多项内容,在作为整体被添加进 set 的过程也仅视作单独一个条目进行处理和计算其 hash 值。(注意:只有不可变类型才能被加入到 set 中)

总之,在 Python 中使用集合进行去重和成员测试非常有效率且方便。但要记住背后实现机制——基于高效但复杂度较高且动态调整大小能力强大的“散列表”。

操作

创建集合

创建一个基本的集合可以使用大括号 {} 或者 set() 函数:

# 使用大括号
my_set = {1, 2, 3}

# 使用 set() 函数
my_set = set([1, 2, 3])

注意:空大括号 {} 不是用来创建空集合的,而是用来创建空字典。要创建一个空集合,你必须使用 set() 而不是 {}

修改

  • 添加元素

    • add(elem):向集合中添加单个元素 elem

      my_set.add(4)
      
  • 更新元素

    • update(*others):将其他集合中的元素添加到当前集合中。参数可以是列表、元组、字典等任何可迭代对象。

      my_set.update([4,5], {6,7})
      
  • 删除元素

    • remove(elem):从集合中移除元素 elem。如果该元素不存在,则抛出 KeyError。

      my_set.remove(1)
      
    • discard(elem):从集合中移除元素 elem。如果该元素不存在,不会发生错误。

      my_set.discard(2)
      
    • pop():随机移除一个元素并返回它。由于 set 是无序的,因此无法确定哪个是“下一个”被删除的项。

      elem = my_set.pop()
      
    • clear():清空整个集合内容。

      my_set.clear()
      

查询

  • 成员测试
    使用关键字 in 来检查某个值是否存在于 set 中。

    if 1 in my_set:
        print("Found!")
    
  • 长度计算
    使用内置函数 len() 来获取 set 的大小(即其中有多少个项)。

    size = len(my_set)
    

数学运算

  • 并集 (union 或者操作符 |):
    合并两个或多个 sets 的所有唯一项。

  • 交叉 (intersection 或者操作符 &):
    找出两个或多个 sets 共有的项。

  • 差异 (difference 或者操作符 -):
    找出存在于第一个 set 中但不在其他 sets 中的所有项。

  • 对称差异 (symmetric_difference 或者操作符 ^):
    找出只存在于其中一个 set 中而不同时存在于两个 sets 中的所有项。

每种数学运算都提供了相应地就地执行版本方法,如:

a.intersection_update(b) # 将 a 更新为 a 和 b 的交叉结果.

这些方法会直接修改原始数据而不返回新值。

代码示例:

# 定义两个示例 set
a = {1, 2, 3}
b = {3, 4, 5}

# 并运算
print(a | b) # 输出 {1, 2, 3, 4, 5}

# 取交运算
print(a & b) # 输出 {3}

# 差运算 (a 中有而 b 中没有)
print(a - b) # 输出 {1, 2}

# 对称差分 (在 a 或 b 中但不同时在 a 和 b 中)
print(a ^ b) # 输出 {1, 2 ,4 ,5}
  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿-瑞瑞

打赏不准超过你的一半工资哦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值