python内置数据结构学习指南
集合(set)
初始化
#list不能存入set中,可变的不能作为key
s1=set()
s2={1,2,3}
s3=set('hello')#{h,e,l,o}
s4=set([list])
#传入一个字典,然后自动就把dict中的所有key组合成一个set
s5=set('name':1) #{'name'}
s6=set{(tuple)}
内置方法
'''
基础操作
'''
s1.add(1) #添加元素,只能是数字、字符串、元组或者布尔类型(True 和 False)值
st.remove(element) #如果被删除元素本就不包含在集合中,则此方法会抛出 KeyError 错误
s1.discard(element) #当删除集合中元素失败时,此方法不会抛出任何错误。
s1.clear() #全部清除
s1.pop() #随机删除
'''
集合操作
`set1={1,2,3}` 和 `set2={3,4,5}`
'''
set <= other#包含于
set < other#真包含于
set >= other#包含
set > other#真包含
isdisjoint(other)#和other的交集为空
x={1,2,3,4}
y={1,2,3,4,5}
z=x.intersection(y) #返回的集合仅包含两个集合中都存在的项目,或者如果使用两个以上的集合进行
A = {1, 2, 3}
B = {3, 4, 5}
union = A.union(B)
print(union) # 输出: {1, 2, 3, 4, 5} 表示集合的并集
计数器(Counter)
Python内建的 collections 集合模块中的 Counter 类能够简洁、高效的实现统计计数。
Counter 是 dict 字典的子类,Counter 拥有类似字典的 key 键和 value 值,只不过 Counter 中的键为待计数的元素,而 value 值为对应元素出现的次数 count,为了方便介绍统一使用元素和 count 计数来表示。虽然 Counter 中的 count 表示的是计数,但是 Counter 允许 count 的值为 0 或者负值。
初始化
必须要进行实例化,在实例化的同时可以为构造函数传入参数来指定不同类型的元素来源。
from colections import Counter
a=Counter()
# 从可迭代对象中实例化 Counter 对象
b = Counter('chenkc')
# 从 mapping 中实例化 Counter 对象
#但是由于字典中的键是唯一的,因此如果字典中的键重复会保留最后一个。
c = Counter({'a':1, 'b':2, 'c':3})
# 从关键词参数中实例化 Counter 对象
#关键词参数中指定的关键词必须是唯一的,但是不同于字典,如果指定的关键词重复,程序会抛出SyntaxError异常。
d = Counter(a = 1, b = 2, c = 3)
内置方法
'''
添加元素
'''
# 实例化元素为空的 Counter
a = Counter()
# 为 Counter 添加元素以及对应的 count 计数
a['a'] = 1 #(‘a’:1)#a[null]=0#没有的元素默认为0,可以直接+1
a['b']+=1
'''
查找元素
在字典中查找不存在的键,程序会抛出 KyeError的异常,但是由于 Counter 用于统计计数,因此 Counter 不同于字典,**如果在 Counter 中查找一个不存在的元素,不会产生异常,而是会返回 0,这其实很好理解,Counter 计数将不存在元素的 count 值设置为 0 **。
'''
'''
elements()函数
返回一个迭代器,可以通过 list 或者其它方法将迭代器中的元素输出,输出的结果为对应出现次数的元素。
elements 函数不会将 0 和负值对应的元素值打印出来。
'''
c = Counter({'a':1, 'b':2, 'c':3})
list(c.elements())
'''
most_common([n])函数
返回一个出现次数从大到小的前 n 个元素的列表。
1. 不输入 `n`,默认返回所有;
2. 输入 `n`小于最长长度,则返回前 `n`个数;
3. 输入 `n`等于最长长度,则返回所有;
4. 输入 `n = -1`,则返回空;
'''
c = Counter({'a':1, 'b':2, 'c':3})
c.most_common()#[('c', 3), ('b', 2), ('a', 1)]
c.most_common(2)#[('c', 3), ('b', 2)]
c.most_common(-1)#[]
'''
### subtract()函数
方法其实就是将两个 Counter 对象中的元素对应的计数相减。
两个 Counter 中的对应的元素的计数相减。当其中某个 Counter 中对应的元素不存在的时候,默认将其计数设置为 0,这也是为什么 `'d'`的计数为-2的原因。
'''
c = Counter({'a':1, 'b':2, 'c':3})
d = Counter({'a':1, 'b':3, 'c':2, 'd':2})
c.subtract(d)
#({'c': 1, 'a': 0, 'b': -1, 'd': -2})
'''
集合运算
'''
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
c + d # add two counters together: c[x] + d[x]
Counter({'a': 4, 'b': 3})
c - d # subtract (keeping only positive counts)
Counter({'a': 2})
c & d # intersection: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
双端队列(deque)
初始化
from collections import deque
dq=deque()
内置方法
append()#右填
appendleft()#左填
clear()#清空
count()#包含value的个数
extend()#右边扩展,可以是列表,元祖或者字典(key)
extendleft()#左边扩展
pop()#移除右边
popleft()#移除左边
remove()#移除队列第一个出现的value元素
reverse()#反转
rotate()#对队列进行移动
字典(dict)
初始化
d=dict() #{}
a=['a','b','c']
b=[1,2,3]
d=dict(zip(a,b)) #{'a': 1, 'b': 2, 'c': 3}
e=dict(a=1,b=2,c=3) #{'a': 1, 'b': 2, 'c': 3}
q=dict([('one',1),('two',2)])
#{'one': 1, 'two': 2}
dict= {x: i for i, x in enumerate(arr)}
查询
- key -- 字典中要查找的键。
- value -- 可选,如果指定键的值不存在时,返回该默认值(None)。
dict.get(key[, value])
dict.get(1,0)
把两个列表合并在一个字典中
key_list=['a','b','c']
values_list=['blue','red','bold']
dict_=dict(zip(key_list,values_list))
默认字典集(defaultdict)
初始化
from collections import defaultdict
dic=defaultdict(int)
dis=defaultdict(list)
dic_1 = defaultdict(int)
dic_2 = defaultdict(tuple)
dic_3 = defaultdict(list)
dic_4 = defaultdict(str)
dic_5 = defaultdict(set)
5.列表(list)
列表推导式
#30以内所有能被3整除的数
multiples = [i for i in range(30) if i % 3 is 0]
#[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
#统计大于target的元素个数
len([x for x in hours if x >= target])
sum(x >= target for x in hours)
30以内所有能被3整除的数的平方
def squared(x):
return x*x
multiples = [squared(i) for i in range(30) if i % 3 is 0]
找到嵌套列表中名字含有两个‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
print([name for lst in names for name in lst if name.count('e') >= 2]) # 注意遍历顺序,这是实现的关键
常用方法
list.insert(idx,val) #插入一个值
有序集合(Ordered-collections)
初始化
from sortedcontainers import SortedList
a=SortedList(['1','2'],key = lambda item:len(item))
基本操作
a.add()
a.remove()#删除元素,元素不存在不会报错
a.discard()#删除元素,元素不存在时不会报错
a.pop()#移除最后一个元素
二分查找
pos_left=a.bisect_left(2)
pos_right=a.bisect_right(2)
pos=a.bisect(2)
优先队列(Priority_queue)
默认最小堆
初始化
res=[]
heap=heapq.heapify(res)#原地,线性时间内。
方法
heapq.heappush(heap, item)
将 item 的值加入 heap 中,保持堆的不变性。
heapq.heappop(heap)
弹出并返回 heap 的最小的元素,保持堆的不变性。如果堆为空,抛出 IndexError 。使用 heap[0] ,可以只访问最小的元素而不弹出它。
heapq.heappushpop(heap, item)
将 item 放入堆中,然后弹出并返回 heap 的最小元素。该组合操作比先调用 heappush() 再调用 heappop() 运行起来更有效率。
heapq.heapreplace(heap, item)
弹出并返回 heap 中最小的一项,同时推入新的 item。 堆的大小不变。 如果堆为空则引发 IndexError。
这个单步骤操作比 heappop() 加 heappush() 更高效,并且在使用固定大小的堆时更为适宜。 pop/push 组合总是会从堆中返回一个元素并将其替换为 item。
返回的值可能会比添加的 item 更大。 如果不希望如此,可考虑改用 heappushpop()。 它的 push/pop 组合会返回两个值中较小的一个,将较大的值留在堆中。
```python
import heapq
# 创建一个空的最小堆
minHeap = []
heapq.heapify(minHeap)
# 创建一个空的最大堆
# 由于Python中并没有内置的函数可以直接创建最大堆,所以一般我们不会直接创建一个空的最大堆。
# 创建带初始值的「堆」, 或者称为「堆化」操作,此时的「堆」为「最小堆」
heapWithValues = [3,1,2]
heapq.heapify(heapWithValues)
# 创建最大堆技巧
# Python中并没有内置的函数可以直接创建最大堆。
# 但我们可以将[每个元素*-1],再将新元素集进行「堆化」操作。此时,堆顶元素是新的元素集的最小值,也可以转换成原始元素集的最大值。
# 示例
maxHeap = [1,2,3]
maxHeap = [-x for x in maxHeap]
heapq.heapify(maxHeap)
# 此时的maxHeap的堆顶元素是-3
# 将-3转换为原来的元素3,既可获得原来的maxHeap中最大的值是3
内置函数
# 最小堆插入元素
heapq.heappush(minHeap, 1)
# 最大堆插入元素
# 元素乘以-1的原因是我们将最小堆转换为最大堆。
heapq.heappush(maxHeap, 1*-1)
# 最小堆获取堆顶元素,即最小值
minHeap[0]
# 最大堆获取堆顶元素,即最大值
# 元素乘以 -1 的原因是:我们之前插入元素时,将元素乘以 -1,所以在获取元素时,我们需要乘以 -1还原元素。
maxHeap[0]*-1
# 最小堆删除堆顶元素
heapq.heappop(minHeap)
# 最大堆删除堆顶元素
heapq.heappop(maxHeap)
# 最小堆的长度
len(minHeap)
# 最大堆的长度
len(maxHeap)
import heapq
def object_queue():
"""
针对对象结构的优先队列
"""
q = []
heapq.heappush(q, (2, 'code'))
heapq.heappush(q, (1, 'eat'))
heapq.heappush(q, (3, 'sleep'))
heapq.heappush(q, (2, 'play'))
heapq.heappush(q, (3, "debug"))
n_smallest = heapq.nsmallest(3, q, key=lambda x: x[0])
print("最小的3个元素:{0}".format(n_smallest))
# 返回最大的 n 个元素,相当于 sorted(iterable, key=key, reverse=True)[:n]
n_largest = heapq.nlargest(3, q, key=lambda x: x[1])
print("最大的3个元素:{0}".format(n_largest))
object_queue(
queue.PriorityQueue
这个优先级队列的实现在内部使用了 heapq
,时间和空间复杂度与 heapq
相同。
区别在于 PriorityQueue
是同步的,提供了锁语义来支持多个并发的生产者和消费者。
在不同情况下,锁语义可能会带来帮助,也可能会导致不必要的开销。不管哪种情况,你都可能更喜欢 PriorityQueue
提供的基于类的接口,而不是使用 heapq
提供的基于函数的接口。
from queue import PriorityQueue
q = PriorityQueue()
q.put((2, 'code'))
q.put((1, 'eat'))
q.put((3, 'sleep'))
while not q.empty():
next_item = q.get()
print(next_item)
# 结果:
# (1, 'eat')
# (2, 'code')
# (3, 'sleep')
自定义优先队列
在面向对象的编程过程中,我们通常是将一些单独的函数或变量组合成一个对象,然后在进行优先级排列。例如我们现在有很多种汽车,汽车有名字和价格,以及一些操作方法。当我们对汽车对象来按照价格进行优先级排列时,由于自定义的对象是不可比较的,所以在进行优先级排列时会报错。因此对于那些自定义的对象,我们需要重写优先级队列的方法来进行实现。
由于 PriorityQueue
也是基于 heapq
实现的,所以我们自定义的优先级队列可以直接基于 heapq
模块来实现。
import heapq
class priorityQueue(object):
def __init__(self):
self.queue=[]
self.index=0
def push(self,item,priority:int)->None:
heapq.heappush(self.queue,(-priority,self.index,item))
self.index+=1
def pop(self):
return heapq.heappop(self.queue)[-1]
def qsize(self):
return len(self.queue)
def empty(self):
return True if not self.queue else False
class Car(object):
def __init__(self,name,value):
self.name=name
self.value=value
def __repr__(self):
return "{0}--{1}".format(self.name,self.value)
if __name__=="__main__":
car1 = Car("BMW", 45)
car2 = Car("Maybach", 145)
car3 = Car("Bugatti", 85)
car4 = Car("Cadillac", 78)
car5 = Car("Maserati", 85)
pq = priorityQueue()
pq.push(car1, car1.value)
pq.push(car2, car2.value)
pq.push(car3, car3.value)
pq.push(car4, car4.value)
pq.push(car5, car5.value)
print("队列大小:{0}".format(pq.qsize()))
# 弹出元素
while not pq.empty():
print(pq.pop())
字符串(str)
内置方法
s.replace(' ','-')
s.replace('one','xxx',2)#只会替换前面匹配的n个字符串。
s = 'one two one two one'
print(s.translate(str.maketrans({'o': 'O', 't': 'T'})))
# One TwO One TwO One
print(s.translate(str.maketrans({'o': 'XXX', 't': None})))
# XXXne wXXX XXXne wXXX XXXne
s.isalnum()
s.isalpha()
s.isdigit()
s.islower()
s.isupper()
s.istitle()
s.isspace()