python的collections库是一个内置模块,提供了除列表、字典、元组和集合等通用数据结构之外的几种数据结构,这些数据结构在某些情况下对数据的处理更为高效。在算法开发或者刷leetcode题的过程中,熟练掌握以下数据结构往往能够事半功倍。
一、deque
deque(双端队列)是一个线程安全、可以快速从两端添加或删除元素的双向列表。deque可以创建一个固定长度的队列,当队列满时,自动删除最旧的元素(设置maxlen参数),这意味着可以用于实现简单的缓存机制或者处理滑动窗口。此外,deque提供了rotate方法,可以将队列中的元素向左或向右旋转,reverse方法则可以原地反转队列中的元素。
from collections import deque
# 初始化deque实例,设置最大容量为3
d = deque([1, 2, 3], maxlen=3)
print(d) # deque([1, 2, 3], maxlen=3)
# 弹出队列最后一个元素
d.pop()
print(d) # deque([1, 2], maxlen=3)
# 弹出队列头部第一个元素
d.popleft()
print(d) # deque([2], maxlen=3)
# 在队列后面插入一个元素
d.append(3)
print(d) # deque([2, 3], maxlen=3)
# 在队列头部插入一个元素
d.appendleft(1)
print(d) # deque([1, 2, 3], maxlen=3)
# 向右旋转队列中的数字(相当于每个元素向右位移n位)
d.rotate(1)
print(d) # deque([3, 1, 2], maxlen=3)
# 向左旋转队列中的数字(每个元素左移n位)
d.rotate(-1)
print(d) # deque([1, 2, 3], maxlen=3)
# 反转整个队列
d.reverse()
print(d) # deque([3, 2, 1], maxlen=3)
# 往队列后面插入一个新的元素,但由于队列最大长度为3,队列头部的元素将被去除
d.append(0)
print(d) # deque([2, 1, 0], maxlen=3)
# # 往队列头部插入一个新的元素,但由于队列最大长度为3,队列最后面的元素将被去除
d.appendleft(3)
print(d) # deque([3, 2, 1], maxlen=3)
二、Counter
Counter是一个计数器,用于统计可哈希对象的频率。它是字典的子类,键是元素,值是元素的计数。Counter最常见的用途是统计元素在可迭代对象(如列表、字符串等)中出现的频率,此外Counter还支持加法、减法、交集和并集等数学运算,可以方便地对多个计数器进行操作。
from collections import Counter
# 创建一个计数器
cnt = Counter(['a', 'b', 'c', 'a', 'b', 'a'])
# 访问计数
print(cnt['a']) # 输出: 3
print(cnt['b']) # 输出: 2
print(cnt['c']) # 输出: 1
# 计数器的其他操作
print(cnt.most_common(2)) # 输出: [('a', 3), ('b', 2)]
# 创建另一个计数器
cnt1 = Counter(['a', 'a', 'c', 'a', 's', 'a'])
# 合并两个计数器
add_cnts = cnt + cnt1
print(add_cnts) # Counter({'a': 7, 'b': 2, 'c': 2, 's': 1})
# 统计两个计数器的差异,在A-B的例子中,统计的是A之于B多出来的元素
minus_cnts = cnt - cnt1
print(minus_cnts) # Counter({'b': 2})
minus_cnts = cnt1 - cnt
print(minus_cnts) # Counter({'a': 1, 's': 1})
# 统计两个计数器的交集
print(cnt & cnt1) # Counter({'a': 3, 'c': 1})
# 统计两个计数器的并集
print(cnt | cnt1) # Counter({'a': 4, 'b': 2, 'c': 1, 's': 1})
三、OrderedDict
OrderedDict是一个有序字典,记录了键值对的插入顺序。OrderedDict可以用于实现最近最少使用缓存(LRU,Least Recently Used),通过将最近访问的元素移动到末尾,可以方便地管理缓存的大小和淘汰策略。另外,在需要比较两个字典的顺序和内容是否相同时,OrderedDict也可以提供准确的比较结果。
from collections import OrderedDict
# 创建一个有序字典
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
# 访问有序字典
for key, value in od.items():
print(key, value)
# a 1
# b 2
# c 3
# 比较两个有序字典是否相同
od1 = OrderedDict()
od1['a'] = 1
od1['b'] = 2
od1['c'] = 3
print(od==od1) # True
# 移动元素到末尾
od.move_to_end('a', last=True)
print(od) # OrderedDict([('b', 2), ('c', 3), ('a', 1)])
print(od==od1) # False
# 移动元素到开头
od.move_to_end('a', last=False)
print(od) # OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 删除并返回最后一个键值对
od.popitem()
print(od) # OrderedDict([('a', 1), ('b', 2)])
# 删除并返回第一个键值对
od.popitem(last=False)
print(od) # OrderedDict([('b', 2)])
四、defaultdict
defaultdict是一个带有默认值的字典,如果在括号中指定int则默认值为0,如果是list则默认值是一个空列表,也可以设置为其他数据类型,如果设置为None,则defaultdict与普通的字典一样。defaultdict的特点是当访问一个不存在的键时,会返回默认值,而不是抛出KeyError异常。
from collections import defaultdict
# 创建一个带有默认值的字典
dd = defaultdict(int)
# 访问不存在的键
print(dd['a']) # 输出: 0
# 设置键值对
dd['b'] = 1
print(dd['b']) # 输出: 1
# 创建一个带有默认值的字典
dd = defaultdict(list)
# 访问不存在的键
print(dd['a']) # 输出: []
# 设置键值对
dd['b'] = [1]
print(dd['b']) # 输出: [1]
五、ChainMap
ChainMap是一个容器类,用于将多个字典或其他映射对象组合在一起,形成一个单一的视图。它在需要在多个字典中查找值时非常有用。
from collections import ChainMap
# 创建多个字典
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
# 创建一个ChainMap
cm = ChainMap(dict1, dict2)
print(cm) # ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4})
# 访问ChainMap
print(cm['a']) # 输出: 1
print(cm['b']) # 输出: 2
print(cm['c']) # 输出: 4
六、namedtuple
namedtuple是一个工厂函数,用于创建具名元组。具名元组类似于普通的元组,但具名元组的每个元素都有一个名称,可以通过名称来访问元素。在需要定义简单的数据结构时,namedtuple可以作为类的替代方案。与类相比,namedtuple更加简洁,不需要编写初始化方法和其他冗长的代码。另外,namedtuple是不可变的,这意味着一旦创建,就不能修改其内容。
from collections import namedtuple
# 定义具名元组类
Person = namedtuple('Person', ['name', 'age', 'gender'])
# 创建具名元组实例
person = Person(name='Alice', age=20, gender='Female')
# 访问元素
print(person.name) # 输出: Alice
print(person.age) # 输出: 20
print(person.gender) # 输出: Female