Python中与C语言STL部分模板的类似模块

C语言中,我们打ACM可以用<vector><stack>等模板来快速实现一些经典的数据结构,可我在很多地方都没找到Python中类似于C里面的STL模板这么好用的东西.于是我在Python的标准库里面总结了些模块来直接实现类似的功能(当然也可能是我真的没找到,如果各位来客有知道的欢迎在评论区留言,确实很需要这类东西),至于这些模块设计出来的初衷是什么,我没有去细究.目前这些模块在我手里只是用来解一些算法题之类的…

对应表:

数据结构和部分方法C语言中对应的模板Python中对应的模块或函数
数组<vector>array.py
双端队列<deque>collections.py
优先队列<queue>queue.py
FIFO队列<queue>queue.py
LIFO队列(栈)<stack>queue.py
<algorithm>heapq.py
排序<stdlib.h>中的qsort()函数sorted()函数

具体用法和实例:

关于STL模板的信息很容易找到,这里主要记录Python对应的办法.
这里所阐述的方法均是本人认为在题解中是很实用的,有些官方文档里面有的但在解题中用不到的并无涉及.想进一步了解直接查看对应的官文档链接.

1.数组:

对应的官方文档链接-array.py

初始化array对象:array.array(typecode[, initializer])
注:该函数接受两个参数,第一个为typecode,指代所定义的数据类型,第二个必须是一个列表对象(可选).
typecode所指代的数据类型:

type codeC TypePython TypeMinimum size in bytes
‘b’signed charint1
‘B’unsigned charint1
‘u’Py_UNICODEUnicode character2
‘h’signed shortint2
‘H’unsigned shortint2
‘i’signed intint2
‘I’unsigned intint2
‘l’signed longint4
‘L’unsigned longint4
‘q’signed long longint8
‘Q’unsigned long longint8
‘f’floatfloat4
‘d’doublefloat8

返回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 the 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: (2572988420504, 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中内置的包),想了解更多去官网-numpy.py.

2.双端队列:

对应的官方文档链接-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)

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)
# 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.优先队列:

对应的官方文档链接 -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()函数作用于一个空的队列时能及时报错

运行结果:

#0
#The priority is empty now.
#23
#12
#33
#54
#34
#21
#9
#23

4.FIFO队列:

对应的官方文档链接-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.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.py

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()函数

对应的官方文档链接-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()函数更复杂的用法可以参考一下这篇博文:https://blog.csdn.net/qq_40438165/article/details/83377190

本人第一次写博文,如有什么不足或有待修改的地方,欢迎来评论区指正.
关于STL的模板还有很多,比如<list><map>等等,本人在之后的探索中如果发现类似功能的Python模块会继续填充.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值