对python的再认识-基于数据结构进行-a007-集合-CURD
Python Set 集合的 CURD
本文聚焦 Python 集合的四大基础操作:增(Create)、查(Read)、删(Delete)、改(Update),包含详细示例与时间复杂度分析。
一、增(Create)
1.1 创建集合
# 空集合(注意:不能用 {} 创建空集合) empty =set()type(empty)# <class 'set'># {} 实际上是空字典 not_empty ={}type(not_empty)# <class 'dict'># 从可迭代对象创建 nums =set([1,2,3,2,1])# {1, 2, 3} - 自动去重# 从字符串创建 chars =set("hello")# {'h', 'e', 'l', 'o'} - 去重,顺序不定# 直接创建(花括号语法) colors ={"red","green","blue"}# {'red', 'green', 'blue'}# 创建单元素集合 single ={1,}# {1}# 从范围创建 range_set =set(range(5))# {0, 1, 2, 3, 4}时间复杂度:set(iterable) 为 O(n),n 为可迭代对象长度1.2 添加单个元素 add()
s ={1,2,3}# 添加元素 s.add(4)# {1, 2, 3, 4}# 添加已存在的元素(无效果,不报错) s.add(3)# {1, 2, 3, 4}# 添加不同类型 s.add("hello") s.add((1,2)) s.add(3.14)# {1, 2, 3, 4, 'hello', (1, 2), 3.14}# ⚠️ 无法添加不可哈希元素# s.add([1, 2]) # TypeError: unhashable type: 'list'# s.add({1, 2}) # TypeError: unhashable type: 'set'时间复杂度:add(x) 为 O(1)(平均情况)1.3 批量添加 update()
s ={1,2,3}# 添加列表中的元素 s.update([4,5,6])# {1, 2, 3, 4, 5, 6}# 添加另一个集合 s.update({7,8,9})# {1, 2, 3, 4, 5, 6, 7, 8, 9}# 添加字符串(逐字符添加) s.update("abc")# {1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c'}# 添加元组 s.update((10,11))# {1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 10, 11}# 添加范围 s.update(range(12,15))# {1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 10, 11, 12, 13, 14}# update 等价于 |= 运算符 s |={15,16}# {1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 10, 11, 12, 13, 14, 15, 16}时间复杂度:update(iter) 为 O(k),k 为添加的元素数量二、查(Read)
2.1 成员检测 in
s ={"apple","banana","cherry"}# in 运算符"apple"in s # True"grape"in s # False# not in 运算符"orange"notin s # True# 检测数字 nums ={1,2,3,4,5}3in nums # True10in nums # False# 检测元组(元组可哈希) points ={(0,0),(1,1),(2,2)}(1,1)in points # True(3,3)in points # False时间复杂度:x in s 为 O(1)(平均情况)2.2 获取元素数量 len()
s ={1,2,3,4,5}# len() 函数len(s)# 5# 空集合len(set())# 0# 去重后的数量 lst =[1,2,2,3,3,3]len(set(lst))# 3时间复杂度:len(s) 为 O(1)2.3 遍历集合
s ={"a","b","c","d"}# for 循环遍历for item in s:print(item)# 注意:集合无序,输出顺序不确定# 使用 enumerate 获取索引for i, item inenumerate(s):print(f"{i}: {item}")# 0: a# 1: b# 2: c# 3: d# (顺序可能不同)# 遍历数字集合 nums ={10,20,30,40,50}for num in nums:print(num *2)# 20, 40, 60, 80, 100(顺序可能不同)时间复杂度:遍历为 O(n),n 为集合大小
2.4 检查集合关系
set_a ={1,2,3} set_b ={1,2,3,4,5} set_c ={1,2}# issubset(): 是否子集 set_c.issubset(set_a)# True set_c.issubset(set_b)# True# <= 运算符:子集(包含自身) set_c <= set_a # True set_a <= set_a # True# < 运算符:真子集(不包含自身) set_c < set_a # True set_a < set_a # False# issuperset(): 是否超集 set_b.issuperset(set_a)# True set_a.issuperset(set_c)# True# >= 运算符:超集(包含自身) set_b >= set_a # True set_a >= set_a # True# > 运算符:真超集(不包含自身) set_b > set_a # True set_a > set_a # False# isdisjoint(): 是否无交集{1,2}.isdisjoint({3,4})# True{1,2}.isdisjoint({2,3})# False时间复杂度:关系检查为 O(min(len(s1), len(s2)))
2.5 复制集合
s ={1,2,3,4,5}# copy() 方法:浅拷贝 s_copy = s.copy()# {1, 2, 3, 4, 5}# 修改原集合不影响副本 s.add(6)print(s)# {1, 2, 3, 4, 5, 6}print(s_copy)# {1, 2, 3, 4, 5}# 等价于 set() 构造函数 s_copy2 =set(s)时间复杂度:copy() 为 O(n)三、删(Delete)
3.1 删除指定元素 remove()
s ={1,2,3,4,5}# 删除元素 s.remove(3)# {1, 2, 4, 5}# 删除多个 s.remove(1) s.remove(5)# {2, 4}# ⚠️ 元素不存在时抛出 KeyError# s.remove(10) # KeyError: 10# 安全删除:先检查if10in s: s.remove(10)else:print("10 不在集合中")时间复杂度:remove(x) 为 O(1)(元素存在时)3.2 安全删除 discard()
s ={1,2,3,4,5}# 删除存在的元素 s.discard(3)# {1, 2, 4, 5}# 删除不存在的元素(不报错) s.discard(10)# {1, 2, 4, 5}# 连续删除 s.discard(1) s.discard(2) s.discard(100)# 不存在,也不报错# {4, 5}时间复杂度:discard(x) 为 O(1)3.3 删除并返回 pop()
s ={1,2,3,4,5}# 删除并返回任意元素 element = s.pop()print(element)# 可能是 1、2、3、4、5 中的任意一个print(s)# 剩余 4 个元素# 连续弹出while s: elem = s.pop()print(f"弹出: {elem}, 剩余: {s}")# 空集合调用 pop 抛出 KeyError# set().pop() # KeyError: pop from an empty set注意:集合无序,pop()删除的是"任意"元素,不是特定位置
时间复杂度:pop()为 O(1)
3.4 清空集合 clear()
s ={1,2,3,4,5}# 清空所有元素 s.clear()print(s)# set()# 验证清空后为空len(s)# 0# 重新赋值 s ={1,2,3} s.clear() s # set()时间复杂度:clear() 为 O(1)3.5 删除多个元素
s ={1,2,3,4,5,6,7,8,9}# difference_update(): 删除多个元素 s.difference_update({2,4,6,8})# {1, 3, 5, 7, 9}# 等价于 -= 运算符 s -={1,9}# {3, 5, 7}# 保留指定元素(删除不在指定集合中的元素) s.intersection_update({3,4,5})# {3, 5}# 保留奇数 odd_set ={1,3,5,7,9} s ={1,2,3,4,5,6,7,8,9} s.intersection_update(odd_set)# {1, 3, 5, 7, 9}时间复杂度:批量删除为 O(len(s_to_remove))
四、改(Update)
集合本身是无序的,没有"修改特定位置元素"的概念。
但可以通过"删除+添加"的方式改变集合内容:
4.1 删除旧值,添加新值
s ={1,2,3,4,5}# 方式:先删除,再添加 s.discard(3) s.add(30)# {1, 2, 4, 5, 30}# 替换多个值 s.discard(1) s.discard(2) s.add(10) s.add(20)# {4, 5, 30, 10, 20}4.2 使用集合运算修改
s ={1,2,3,4,5}# 并集:添加多个元素 s = s |{10,20,30}# {1, 2, 3, 4, 5, 10, 20, 30}# 交集:只保留指定元素 s = s &{2,4,6,8}# {2, 4}# 差集:删除指定元素 s = s -{4}# {2}# 对称差:保留不共有的元素 s = s ^{2,3,4}# {3, 4}4.3 原地修改运算符
a ={1,2,3} b ={3,4,5}# 原地并集(修改 a) a |= b print(a)# {1, 2, 3, 4, 5}# 原地交集 a &={2,4,6}print(a)# {2, 4}# 原地差集 a -={4}print(a)# {2}# 原地对称差 a ^={2,3,4}print(a)# {3, 4}五、集合运算(交并差补)
5.1 并集(Union)
a ={1,2,3} b ={3,4,5} c ={5,6,7}# union() 方法 result = a.union(b)# {1, 2, 3, 4, 5}# | 运算符 result = a | b # {1, 2, 3, 4, 5}# 多个集合的并集 result = a | b | c # {1, 2, 3, 4, 5, 6, 7} result = a.union(b, c)# {1, 2, 3, 4, 5, 6, 7}时间复杂度:O(len(a) + len(b))
5.2 交集(Intersection)
a ={1,2,3,4} b ={3,4,5,6} c ={4,5,6}# intersection() 方法 result = a.intersection(b)# {3, 4}# & 运算符 result = a & b # {3, 4}# 多个集合的交集 result = a & b & c # {4} result = a.intersection(b, c)# {4}时间复杂度:O(min(len(a), len(b)))
5.3 差集(Difference)
a ={1,2,3,4,5} b ={4,5,6,7}# difference() 方法:a 有但 b 没有的 result = a.difference(b)# {1, 2, 3}# - 运算符 result = a - b # {1, 2, 3}# 反向差集:b 有但 a 没有的 result = b - a # {6, 7}# ⚠️ 差集不满足交换律print(a - b == b - a)# False(通常)时间复杂度:O(len(a))
5.4 对称差集(Symmetric Difference)
什么是对称差?
对称差:返回只在一个集合中出现的元素,即"非共有"元素。
图解示意: 集合 A: ████████░░░░░░ 集合 B: ░░░░░░████████ ──────── 并集 (A | B): ██████████████ (所有元素) 交集 (A & B): ░░░░░░░░░░░░░░░ (共有元素) 对称差 (A ^ B): ████████░░░████ (只在一个集合中的) ──────── ──── 基础用法
a ={1,2,3,4} b ={3,4,5,6}# symmetric_difference() 方法 result = a.symmetric_difference(b)# {1, 2, 5, 6}# 解释:1,2 只在 a 中;5,6 只在 b 中;3,4 在两者中(被排除)# ^ 运算符(更简洁) result = a ^ b # {1, 2, 5, 6}与其他运算对比
a ={1,2,3,4} b ={3,4,5,6}print(f"A: {a}")# {1, 2, 3, 4}print(f"B: {b}")# {3, 4, 5, 6}print(f"并集: {a | b}")# {1, 2, 3, 4, 5, 6} - 所有元素print(f"交集: {a & b}")# {3, 4} - 共有元素print(f"差集: {a - b}")# {1, 2} - a 有 b 没有print(f"差集: {b - a}")# {5, 6} - b 有 a 没有print(f"对称差: {a ^ b}")# {1, 2, 5, 6} - 只在一个集合中等价表达式
# 对称差 = 并集 - 交集 result =(a | b)-(a & b)# {1, 2, 5, 6}# 对称差 = (a-b) 的并集 (b-a) result =(a - b)|(b - a)# {1, 2, 5, 6}实际应用场景
# 1. 找出变化:比较新旧版本 old_version ={"a","b","c","d"} new_version ={"b","c","e","f"}# 所有变化的项(新增+删除) changed = old_version ^ new_version # {'a', 'd', 'e', 'f'}# a, d 是删除的;e, f 是新增的# 2. 找出独有元素 group_a ={"苹果","香蕉","橙子"} group_b ={"香蕉","葡萄","西瓜"}# 只在一个组中出现的水果 exclusive = group_a ^ group_b # {'苹果', '橙子', '葡萄', '西瓜'}# 香蕉在两组都有,所以不在结果中# 3. 比较两个集合的差异 set1 ={1,2,3,4,5} set2 ={4,5,6,7,8}# 找出不同的元素 different = set1 ^ set2 # {1, 2, 3, 6, 7, 8}# 4. 多个集合的对称差 a ={1,2} b ={2,3} c ={3,4}# 链式对称差 result = a ^ b ^ c # {1, 4}# 解释:出现奇数次的元素保留,出现偶数次的去除# 1 出现 1 次 → 保留# 2 出现 2 次 → 去除# 3 出现 2 次 → 去除# 4 出现 1 次 → 保留原地对称差
a ={1,2,3,4}# 原地修改 a a ^={3,4,5,6}# a: {1, 2, 5, 6}# 等价于 a.symmetric_difference_update({3,4,5,6})时间复杂度:O(len(a) + len(b))
5.5 集合运算汇总
| 运算 | 方法 | 运算符 | 描述 | 返回新集合 | 原地运算符 |
|---|---|---|---|---|---|
| 并集 | union() | | (竖线) | 两集合所有元素 | ✅ | |= |
| 交集 | intersection() | & (且号) | 两集合共有的元素 | ✅ | &= |
| 差集 | difference() | - (减号) | a 有但 b 没有的 | ✅ | -= |
| 对称差 | symmetric_difference() | ^ (脱字符) | 只在一个集合中的 | ✅ | ^= |
运算符说明:
|或|:并集(键盘上 Enter 键上方的那个键)&:交集(Shift + 7)^:对称差(Shift + 6)-:差集(减号)
# 快速示例 a ={1,2} b ={2,3} a | b # {1, 2, 3} 并集 a & b # {2} 交集 a - b # {1} 差集 a ^ b # {1, 3} 对称差5.6 原地运算符
a ={1,2,3} b ={3,4,5}# 原地并集(a |= b 修改 a,不返回新集合) a |= b # a: {1, 2, 3, 4, 5}# 等价于 a.update(b)# 原地交集 a &={2,4,6}# a: {2, 4}# 等价于 a.intersection_update({2, 4, 6})# 原地差集 a -={4}# a: {2}# 等价于 a.difference_update({4})# 原地对称差 a ^={2,3,4}# a: {3, 4}# 等价于 a.symmetric_difference_update({2, 3, 4})优势:原地运算符更高效,不创建新集合
六、操作复杂度总结
| 操作 | 方法/运算符 | 平均复杂度 | 说明 |
|---|---|---|---|
| 创建 | set(iterable) | O(n) | n 为可迭代对象长度 |
| 添加 | add(x) | O(1) | 均摊 |
| 批量添加 | update(iter) | O(k) | k 为添加长度 |
| 成员检测 | x in s | O(1) | 平均 |
| 长度 | len(s) | O(1) | |
| 删除 | remove(x) | O(1) | 元素存在时 |
| 安全删除 | discard(x) | O(1) | |
| 弹出 | pop() | O(1) | 删除任意元素 |
| 清空 | clear() | O(1) | |
| 复制 | copy() | O(n) | n 为集合大小 |
| 遍历 | for x in s | O(n) | n 为集合大小 |
| 并集 | s1 | s2 | O(m+n) | m, n 为两集合长度 |
| 交集 | s1 & s2 | O(min(m,n)) | 遍历较小集合 |
| 差集 | s1 - s2 | O(m) | m 为 s1 长度 |
| 对称差 | s1 ^ s2 | O(m+n) | m, n 为两集合长度 |
| 关系检查 | issubset/issuperset | O(min(m,n)) | 子集/超集检查 |
七、总结
| 操作类别 | 方法/运算符 | 要点 |
|---|---|---|
| 创建 | set(), {} | set() 创建空集合,{} 创建空字典 |
| 添加 | add(), update() | add() 单个 O(1),update() 批量 O(k) |
| 删除 | remove(), discard(), pop(), clear() | remove() 元素不存在报错,discard() 不报错 |
| 查询 | in, len(), 遍历 | in 检测 O(1),len() O(1) |
| 关系 | issubset(), issuperset(), isdisjoint() | 子集/超集/无交集判断 |
| 并集 | |, union() | 两集合所有元素 |
| 交集 | &, intersection() | 两集合共有元素 |
| 差集 | -, difference() | a 有 b 没有 |
| 对称差 | ^, symmetric_difference() | 只在一个集合中 |
| 原地运算 | |=, &=, -=, ^= | 修改原集合,更高效 |