C语言中,我们打ACM可以用<vector>、<stack>等模板来快速实现一些经典的数据结构,可我在很多地方都没找到Python中类似于C里面的STL模板这么好用的东西.于是我在Python的标准库里面总结了些模块来直接实现类似的功能(当然也可能是我真的没找到,如果各位来客有知道的欢迎在评论区留言,确实很需要这类东西),至于这些模块设计出来的初衷是什么,我没有去细究.目前这些模块在我手里只是用来解一些算法题之类的…
目录
1.数组array.array
2.双端队列collections.deque
3.优先队列quque.PriorityQueue
4.FIFO队列quque.Queue
5.LIFO队列queue.LifoQueue
6.堆heapq
7.sorted()函数
对应表:
具体用法和实例:
关于STL模板的信息很容易找到,这里主要记录Python对应的办法.
这里所阐述的方法均是本人认为在题解中是很实用的,有些官方文档里面有的但在解题中用不到的并无涉及.想进一步了解直接查看对应的官文档链接。
1.数组array.array
array — Efficient arrays of numeric values — Python 3.7.14 documentationhttps://docs.python.org/3.7/library/array.html?highlight=array#module-array
- 初始化array对象:
array.array(typecode[, initializer])
- 注:该函数接受两个参数,第一个为
typecode
,指代所定义的数据类型,第二个必须是一个列表对象(可选). typecode
所指代的数据类型:
- 注:该函数接受两个参数,第一个为
- 返回array对象中每个元素的字节长(bytes):array.itemsize
- 在数组末尾添加新的元素:array.append(x)
- 查看数组的基本信息:array.buffer_info()
- 注:这会返回一个元组对象,第一个元素对应该数组的地址,第二个对应该数组的元素个数
- 返回元素x在数组中出现的次数:array.count(x)
- 从别的可迭代对象抽出元素添加到数组的尾部(该对象元素数据类型与数组的元素数据类型必须相同!):array.extend(iterable)
- 在尾部增加新的列表里面的所有元素,等价于for x in list:a.append(x),array.fromlist(list)
- 返回数组中元素x首次出现的索引下标:array.index(x)
- 在下标为i的位置插入元素x:array.insert(i, x)
- 删除并返回数组中下表为i的元素,若不填i,默认返回最后一个元素:array.pop([i])
- 删除数组中的第一个x元素:array.remove(x)
- 倒置整个数组中的元素顺序:array.reverse()
- 将数组对象转换为列表对象:array.tolist()
- 将数组转换为机器值数组,并返回字节表示形式:array.tobytes()
示例代码:
import array
x=array.array('i',[1,2,3,4,5])
print(type(x))
print('The size of an element in array (in bytes):',x.itemsize)#返回数组内部每个元素的比特大小
x.append(6)
print('Add 6 at the end of the array:',x)
print('The basic information of the array:',x.buffer_info())#返回一个元祖,第一个元素是该数组当前的内存地址,第二个元素是数组当前的元素数目
x.append(3)
x.append(3)
print('We appended two 3 in the end of the array:',x)
print('The times of 3 occuried in the array:',x.count(3))#返回数组中3出现的次数
x.fromlist([10,11,12])#等价于for x in list: a.append(x).在尾部增加新的列表里面的所有元素
print('We add the elements of list [10,11,12] at the end of the array:',x)
print('The index of the 3 which occured in the first time in the array:',x.index(3))#返回数组中3首次出现的索引下标
x.insert(5,100)#在下标为5的位置插入元素100
print('We inserted the value 100 as the sixth element in the array:',x)
y=x.pop()#删除并返回尾部元素
print(x,'deleted element:',y)
y2=x.pop(2)#删除并返回下标为2的元素
print(x,'delete element indexed 2:',y2)
x.remove(3)#删除数组中第一个3
print(x,'The first 3 was deleted.')
x.reverse()#颠倒数组中的各元素顺序
print(x,'The array was reversed.')
a=x.tolist()#把数组对象转换为列表对象
print(a,type(a))
c=x.tobytes()#将数组转换为机器值数组,并返回字节表示形式
print(c,type(c))
x.extend((12,56,78))#从别的可迭代对象抽出元素添加到数组的尾部(该对象元素数据类型与数组的元素数据类型必须相同!)
print(x)
运行结果:
<class 'array.array'>
The size of an element in array (in bytes): 4
Add 6 at the end of the array: array('i', [1, 2, 3, 4, 5, 6])
The basic information of the array: (2095870696016, 6)
We appended two 3 in the end of the array: array('i', [1, 2, 3, 4, 5, 6, 3, 3])
The times of 3 occuried in the array: 3
We add the elements of list [10,11,12] at the end of the array: array('i', [1, 2, 3, 4, 5, 6, 3, 3, 10, 11, 12])
The index of the 3 which occured in the first time in the array: 2
We inserted the value 100 as the sixth element in the array: array('i', [1, 2, 3, 4, 5, 100, 6, 3, 3, 10, 11, 12])
array('i', [1, 2, 3, 4, 5, 100, 6, 3, 3, 10, 11]) deleted element: 12
array('i', [1, 2, 4, 5, 100, 6, 3, 3, 10, 11]) delete element indexed 2: 3
array('i', [1, 2, 4, 5, 100, 6, 3, 10, 11]) The first 3 was deleted.
array('i', [11, 10, 3, 6, 100, 5, 4, 2, 1]) The array was reversed.
[11, 10, 3, 6, 100, 5, 4, 2, 1] <class 'list'>
b'\x0b\x00\x00\x00\n\x00\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00d\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00' <class 'bytes'>
array('i', [11, 10, 3, 6, 100, 5, 4, 2, 1, 12, 56, 78])
二维数组的创作只能用一个列表来包含多个数组对象来实现了,array不能像<vector>
一样有专门的扩展方案.在Python中有一个第三方包叫numpy.py
在科学计算上要比array.py
先进得多,可它不能用在打算法比赛上(比赛中只能导入Python中内置的包),想了解更多去Contributing to NumPy — NumPy v1.23 Manualhttps://numpy.org/doc/stable/dev/
2.双端队列collections.deque
collections — Container datatypes — Python 3.7.14 documentationhttps://docs.python.org/3.7/library/collections.html?highlight=deque#collections.deque对应的方法:
- collections.deque([iterable[, maxlen]]):定义双端队列
- iterable为任意可迭代对象,
- maxlen指定队列所能包含元素的个数
- append(x):队列尾部添加元素
- appendleft(x):队首添加元素
- clear():清空队列
- copy():为队列创造浅复制
- count(x):返回队列中元素x的个数
- extend(iterable):在队列右端依次添加指定的可迭代对象的所有元素
- extendleft(iterable):在队列左端依次添加指定的可迭代对象的所有元素
- index(x[, start[, stop]]):有三个参数,x,start和stop,没有后两者的情况下返回元素x在队列中的的下标,若有,则在[start:stop]索引范围中寻找元素x的下标,若没找到则报错.
- insert(i, x):在下标为i的位置插入元素x.
- pop(): 删除并返回队尾元素
- popleft:删除并返回队首元素
- remove(value):删除队列中第一个值为value的元素
- reverse():倒置整个队列中的元素顺序
- rotate(n=1):n默认为1,指将队列末端的一个元素移动到队列首端,n为正数时指将队列末端的n个元素移动到队列首端,n为负数时指将队列首端的n个元素移动到队列末端
实例代码:
from collections import*
a=deque(maxlen=25)#提前指定新定义的双端队列长为10.
a.append(1)#在右端增加元素
a.append(2)
a.append(3)
a.append(4)
a.append(5)
print('After right append operation:',a)
for left in range(6,11):
a.appendleft(left)#在左端添加元素
print('After left append operation:',a)
b=a.copy()#创造一个浅复制
print('After copy a to b operation :',b)
b.clear()#清空队列b
print('After clear operation:',b)
print('old deque:',a)
for x in range(5): b.append(12)
print('Count 12 in deque b:',b.count(12))#返回队列b中元素12的个数
print('Before extend operation:',b)
b.extend((1,2,3,4,5))#在队列b右端合并某个可迭代对象的所有元素
print('After extend operation:',b)
print('Position of the first 12 occur in deque b:',b.index(12))#返回b中第一个12出现的索引下标
print('Position of the first 1 occur in deque b[0:6]:',b.index(1,0,6))#指定搜索范围为索引下标0到7,找出1在此范围中第一次出现的位置
b.insert(3,78)#在b的下标为3的位置上插入元素78
print('After insert operation:',b)
c=b.pop()#从b的右端删除并提取一个元素
print('After right pop operation:',c,b)
c=b.popleft()#从b的左边删除并提取一个元素
print('After left pop operation:',c,b)
b.remove(1)#删除b中第一个值为1的元素
print('After remove operation:',b)
b.reverse()#将b的序列倒置
print('After reverse operation:',b)
print('The max len of b:',b.maxlen)#返回b的最大长度,如果没有指定则返回None
b.rotate(3)#将b的队尾3个元素移动到队头
print('After rotate(+) operation:',b)
b.rotate(-2)#将b的队头2个元素移动到队尾
print('After rotate(-) operation:',b)
运行结果:
After right append operation: deque([1, 2, 3, 4, 5], maxlen=25)
After left append operation: deque([10, 9, 8, 7, 6, 1, 2, 3, 4, 5], maxlen=25)
After copy a to b operation : deque([10, 9, 8, 7, 6, 1, 2, 3, 4, 5], maxlen=25)
After clear operation: deque([], maxlen=25)
old deque: deque([10, 9, 8, 7, 6, 1, 2, 3, 4, 5], maxlen=25)
Count 12 in deque b: 5
Before extend operation: deque([12, 12, 12, 12, 12], maxlen=25)
After extend operation: deque([12, 12, 12, 12, 12, 1, 2, 3, 4, 5], maxlen=25)
Position of the first 12 occur in deque b: 0
Position of the first 1 occur in deque b[0:6]: 5
After insert operation: deque([12, 12, 12, 78, 12, 12, 1, 2, 3, 4, 5], maxlen=25)
After right pop operation: 5 deque([12, 12, 12, 78, 12, 12, 1, 2, 3, 4], maxlen=25)
After left pop operation: 12 deque([12, 12, 78, 12, 12, 1, 2, 3, 4], maxlen=25)
After remove operation: deque([12, 12, 78, 12, 12, 2, 3, 4], maxlen=25)
After reverse operation: deque([4, 3, 2, 12, 12, 78, 12, 12], maxlen=25)
The max len of b: 25
After rotate(+) operation: deque([78, 12, 12, 4, 3, 2, 12, 12], maxlen=25)
After rotate(-) operation: deque([12, 4, 3, 2, 12, 12, 78, 12], maxlen=25)
3.优先队列quque.PriorityQueue
queue — A synchronized queue class — Python 3.7.14 documentationhttps://docs.python.org/3.7/library/queue.html?highlight=queue%20priorityqueue#queue.PriorityQueue
- queue.PriorityQueue(maxsize=0):定义一个优先队列,maxsize指定该队列最大元素数
- Queue.qsize():返回队列中现有元素个数
- Queue.empty():返回队列是否为空的布尔值
- Queue.full():返回队列是满元的布尔值
- Queue.put(item, block=True, timeout=None):将元素item放入队列中,
- block代指是否在put()进程出错时打断进程
- timeout指代是否允许进程超时运行.
- (block和timeout在打比赛时没用到过)
- Queue.get(block=True, timeout=None):从队列中删除并返回(或称取出)第一个元素
实例代码:
import queue
priority=queue.PriorityQueue(10)#
print(priority.qsize())
if priority.empty():
print('The priority is empty now.')
for item in [(2,12),(1,23),(4,54),(3,33),(5,34),(8,23),(6,21),(7,9)]:
priority.put(item)#按照第一个元素优先排序
for x in range(priority.qsize()):
print(priority.get(timeout=True)[1])#timeout默认状态下为False,用于get()函数作用于一个空的队列时能及时报错
print('*'*10)
q1=queue.PriorityQueue(10)
q1.put(2)
q1.put(5)
q1.put(3)
q1.put(1)
q1.put(3)#默认排序,升序
for x in range(q1.qsize()):
print(q1.get(timeout=True))
运行结果:
0
The priority is empty now.
23
12
33
54
34
21
9
23
**********
1
2
3
3
5
4.FIFO队列quque.Queue
queue — A synchronized queue class — Python 3.7.14 documentationhttps://docs.python.org/3.7/library/queue.html?highlight=queue#queue.Queue
- queue.Queue(maxsize=0):定义一个FIFO队列,maxsize指定该队列最大元素数
- Queue.qsize():返回队列中现有元素个数
- Queue.empty():返回队列是否为空的布尔值
- Queue.full():返回队列是满元的布尔值
- Queue.put(item, block=True, timeout=None):将元素item放入队列中,block代指是否在put()进程出错时打断进程,timeout指代是否允许进程超时运行.(block和timeout在打比赛时没用到过)
- Queue.get(block=True, timeout=None):从队列中删除并返回(或称取出)第一个元素
代码演示:
import queue
fifo=queue.Queue(10)#提前指明该队列将存储多少元素
print(fifo.qsize())
if fifo.empty():
print('The fifo is empty now.')
for item in range(7):
fifo.put(item)
print(fifo.qsize())
if fifo.full()==True:
print('The fifo is full.')
li=[]
for x in range(7):
li.append(fifo.get())
print(fifo.empty())
print(li)
运行结果:
0
The fifo is empty now.
7
True
[0, 1, 2, 3, 4, 5, 6]
5.LIFO队列queue.LifoQueue
queue — A synchronized queue class — Python 3.7.14 documentationhttps://docs.python.org/3.7/library/queue.html?highlight=queue%20lifoqueue#queue.LifoQueue
- queue.LifoQueue(maxsize=0):定义一个LIFO队列,maxsize指定该队列最大元素数
- Queue.qsize():返回队列中现有元素个数
- Queue.empty():返回队列是否为空的布尔值
- Queue.full():返回队列是满元的布尔值
- Queue.put(item, block=True, timeout=None):将元素item放入队列中,block代指是否在put()进程出错时打断进程,timeout指代是否允许进程超时运行.(block和timeout在打比赛时没用到过)
- Queue.get(block=True, timeout=None):从队列中删除并返回(或称取出)第一个元素
实现代码:
import queue
lifo=queue.LifoQueue(10)
print(lifo.qsize())
if lifo.empty():
print('The lifo is empty now.')
for item in range(10):
lifo.put(item)
print(lifo.qsize())
if lifo.full()==True:
print('The lifo is full.')
li=[]
for x in range(7):
li.append(lifo.get())
print(lifo.empty())
print(li)
运行结果:
0
The lifo is empty now.
10
The lifo is full.
False
[9, 8, 7, 6, 5, 4, 3]
6.堆heapq
https://docs.python.org/3.7/library/heapq.html?highlight=heapq#module-heapqhttps://docs.python.org/3.7/library/heapq.html?highlight=heapq#module-heapq
- heapq.heapify(x):线性时间内把列表x转换为堆,x必须是列表对象.
- heapq.heappush(heap, item):把元素item加入堆heap中,并维持堆的数据结构特性.
- heapq.heappop(heap):从堆heap中删除并返回(又称弹出)最小的元素,并保持堆的稳定性.
- heapq.heappushpop(heap, item):向堆heap中先插入元素item再弹出最小元素.
- heapq.heapreplace(heap, item):先弹出最小元素,再将元素item压入堆heap中.若该堆原先为空堆,则直接报错.
- heapq.merge(*iterables, key=None, reverse=False):将多个可迭代对象合并成一个堆,并返回一个可迭代对象的地址.key代指比较方式(和sorted()函数中的key类似),reserve代指是否反序排序堆.
- heapq.nlargest(n, iterable, key=None)从可迭代对象中返回前n个最大的元素.
- heapq.nsmallest(n, iterable, key=None):从可迭代对象中返回前n个最小的元素.
示例代码:
from heapq import*
heap=[]#定义预处理序列
for x in [12,2,5,8,3,1,4]:
heappush(heap,x)#将元素压入堆中
print('The heap is:',heap)
a=heappop(heap)#弹出最小项
print('The smallest element in the heap is:',a)
print('After pop the smallest one in the heap:',heap)
a=heappushpop(heap,23)#向heap中插入元素23后弹出最小项
print('After heappushpop operation:',heap,'And the smallest one before heappushpop operation:',a)
normal_list=[1,5,4,7,6,2,3]
print('Before heapify operation:',normal_list)
heapify(normal_list)#将x列表放入堆中,heapify函数只能接受list对象作为参数
print('After heapify operation:',normal_list)
Min=heapreplace(heap,12)#先弹出最小项,再将元素12压入堆中,若该堆最开始是空的,则报错
print('After heapreplace operation:',heap,'And the smallest one before heapreplace operation:',Min)
finally_heap_iter=merge(normal_list,heap)#将两个经过堆排序的对象合并成一个堆,并返回其可迭代对象
fin_list=[]
print('Finally merge result:',end=' ')
for item in finally_heap_iter:
print(item,end=' ')
fin_list.append(item)
print()
print('Top 4 largest:',nlargest(4,fin_list))#返回堆中最大的前4项的列表形式
print('Top 4 smallest:',nsmallest(4,fin_list))#返回堆中最小的前4项的列表形式
def heapsort(iterable):#实现普通堆排序,将任何可迭代对象作为参数传递给该函数
h=[]
for value in iterable:
heappush(h,value)
return [heappop(h) for i in range(len(h))]
print('After heapsort:',heapsort(fin_list))
#复杂堆结构:
h = []
heappush(h, (5, 1,'write code'))#遇到可迭代对象,heappush会根据可迭代对象的第一个元素来安排堆
heappush(h, (7, 2,'release product'))
heappush(h, (1, 3,'write spec'))
heappush(h, (3, 4,'create tests'))
heappush(h, (2, 5,'yrite code2'))
heappush(h, (8, 6,'release product2'))
heappush(h, (4, 7,'zrite spec2'))
heappush(h, (6, 8,'create tests2'))
print(nsmallest(3,h,key=lambda x:x[1]))#按照第二个元素大小排序
print(nlargest(3,h,key=lambda x:x[2][0]))#按照第三个元素的开头字母排序
运行结果:
The heap is: [1, 3, 2, 12, 8, 5, 4]
The smallest element in the heap is: 1
After pop the smallest one in the heap: [2, 3, 4, 12, 8, 5]
After heappushpop operation: [3, 8, 4, 12, 23, 5] And the smallest one before heappushpop operation: 2
Before heapify operation: [1, 5, 4, 7, 6, 2, 3]
After heapify operation: [1, 5, 2, 7, 6, 4, 3]
After heapreplace operation: [4, 8, 5, 12, 23, 12] And the smallest one before heapreplace operation: 3
Finally merge result: 1 4 5 2 7 6 4 3 8 5 12 23 12
Top 4 largest: [23, 12, 12, 8]
Top 4 smallest: [1, 2, 3, 4]
After heapsort: [1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 12, 12, 23]
[(5, 1, 'write code'), (7, 2, 'release product'), (1, 3, 'write spec')]
[(4, 7, 'zrite spec2'), (2, 5, 'yrite code2'), (1, 3, 'write spec')]
7.sorted()函数
Sorting HOW TO — Python 3.7.14 documentationhttp://官方链接sorted()
sorted(iterable, *, key=None, reverse=False)
:该函数一般接受三个参数,- 第一个是待排序的可迭代对象,
- 第二个是排序的方式,
- 第三个是一个布尔值,控制是否按倒序排列。
实例代码:
x=[5,2,3,1,4]
x1=sorted(x)
x2=sorted(x,key=lambda item:-item)
x3=sorted(x,reverse=True)
print('正序结果:',x1)
print('逆序结果:',x2)
print('逆序结果2:',x3)
dictory={1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'}
print('字典排序结果:',sorted(dictory))#任意可变的可迭代对象都可以使用sorted()函数
x.sort()
print('.sort()结果:',x)#对列表而言,可以使用.sort()方法进行排序
# print(dictory.sort())#但.sort()方法只能用于列表.该段代码会报错!
#Key的妙用:
print(sorted("This is a test string from Andrew".split(), key=str.lower))#用key来设置不区分大小写排序字符的排序方式
student_tuples=[('john', 'A', 15),('jane', 'B', 12),('dave', 'B', 10)]
print('1: ',sorted(student_tuples,key=lambda student:student[2]))#1.用key来设置按照元组元素的第三个元素来排序
class Student:
def __init__(self,name,grade,age):
self.name=name
self.grade=grade
self.age=age
def __repr__(self):
return repr((self.name, self.grade, self.age))
student_objects=[Student('john', 'A', 15),Student('jane', 'B', 12),Student('dave', 'B', 10)]
print('2: ',sorted(student_objects, key=lambda student: student.age))#2.用key设置按age排序student对象
#itemgetter, attrgetter方式排序:
from operator import itemgetter, attrgetter
print('3: ',sorted(student_tuples, key=itemgetter(2)))#3.itemgetter设置按照元组元素的第三个元素来排序
print('4: ',sorted(student_objects, key=attrgetter('age')))#4.attrgetter设置按照对象的age属性来排序
print('5: ',sorted(student_tuples, key=itemgetter(1,2)))#5.itemgetter设置先按照元组元素的第二个元素排序,若相同再按照第三个元素排序
print('6: ',sorted(student_objects, key=attrgetter('grade','age')))#6.attrgetter设置先按照对象的grade属性来排序,若该属性相同,再比较age属性的值
#倒序排序:
print('7: ',sorted(student_tuples, key=itemgetter(2), reverse=True))#7.倒序排序
print('8: ',sorted(student_objects, key=attrgetter('age'), reverse=True))#8.倒序排序
运行结果:
正序结果: [1, 2, 3, 4, 5]
逆序结果: [5, 4, 3, 2, 1]
逆序结果2: [5, 4, 3, 2, 1]
字典排序结果: [1, 2, 3, 4, 5]
.sort()结果: [1, 2, 3, 4, 5]
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
1: [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
2: [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
3: [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
4: [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
5: [('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
6: [('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
7: [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
8: [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
关于sorted()函数更复杂的用法可以参考一下这篇博文:python sorted函数高级用法_程勇uestc的博客-CSDN博客_python sorted函数返回值
关于STL的模板还有很多,比如<list>
、<map>
等等,本人在之后的探索中如果发现类似功能的Python模块会继续填充.