目录
一、队列
1、循环队列
2、Python队列的三种实现方式
3、例题——队列操作
4、优先队列
(1)基本操作
(2)例题(lanqiaoOJ题号1228)
二、栈
1、用 list 实现栈
2、用 collections.deque 实现栈
3、用 queue.LifoQueue 实现栈
4、例题(lanqiaoOJ题号2117)
(1)暴力法
(2)栈
一、队列
【队列】
先进先出
只能从队头离开队列
只能从队尾进入队列
【缺点】
队列的查找慢,从头到尾一个个查找
1、循环队列
- 用一组连续的存储单元依次存放队列元素
- head 指示队列头元素
- rear 指向尾元素
- 当 head 和 rear 走到底时,下一步回到开始的位置,从而在这组连续空间内循环。
2、Python队列的三种实现方式
【实现方式】
① 用 queue 实现队列操作。有 q.size()、q.empty()、q.put()、q.get() 等功能。
② 列表 list 就是一个普通队列。
③ collections.deque。 deque最快,快30倍。
Queue常用的方法:
① qsize() 获取队列的元素个数。
② put(item [,block[, timeout]]) 往queue中放一个item
③ get(item [,block[, timeout]]) 从queue中取出一个item,并在队列中删除的这个item
3、例题——队列操作
用 queue 实现队列:
from queue import *
q=Queue()
n=eval(input())
for i in range(n):
s=list(map(int,input().split()))
if s[0]==1:
q.put(s[1])
elif s[0]==2:
if not q.empty():
a=q.get()
print(a)
else:
print('no')
break
elif s[0]==3:
print(q.qsize())
7
1 19
1 56
2
19
3
1
2
56
3
0
2
no
>>>
用 list 实现队列:
n=eval(input())
q=[]
for i in range(n):
s=list(map(int,input().split()))
if s[0]==1:
q.append(s[1])
elif s[0]==2:
if len(q)>0:
q.reverse()
a=q.pop()
print(a)
q.reverse()
else:
print('no')
break
elif s[0]==3:
print(len(q))
用 deque 实现队列:
from collections import *
n=eval(input())
q=deque()
for i in range(n):
s=list(map(int,input().split()))
if s[0]==1:
q.append(s[1])
elif s[0]==2:
if len(q)>0:
a=q.popleft()
print(a)
else:
print('no')
break
elif s[0]==3:
print(len(q))
4、优先队列
- 很多算法需要用到一种特殊的队列:优先队列。它的特点是:最优数据始终位于队列头部。
- 优先队列的效率很高:新数据插入队列生成新的最优队头,计算复杂度是 O(logn);
- 弹出最优的队头后在队列中计算出新的最优队头,计算复杂度也是 O(logn)。
(1)基本操作
PriorityQueue 的基本操作:
pq = queue.PriorityQueue()
pq.put ([priority, value]) #进队列
pq.get () #取出队首。
put 函数的第一个参数 priority 表示数据的优先级,第二个参数 value 是值,值越小优先级越高。队首总是最小值。
import queue
pq = queue.PriorityQueue()
pq.put([1,'abc'])
pq.put([7,998])
pq.put([5,True])
while not pq.empty():
print(pq.get(),end=' ')
(2)例题(lanqiaoOJ题号1228)
【题目描述】
小明买了 n 件白色的衣服,他希望对这些衣服进行染色,每次染色时,他会将某种颜色的所有衣服寄去染色厂,第 i 件衣服的邮费为 ai 元,染色厂会按照小明的要求将其中一部分衣服染成同一种任意的颜色,之后将衣服寄给小明,请问小明要将 n 件衣服染成不同颜色的最小代价是多少?
【输入描述】
第一行为一个整数 n,表示衣服的数量。第二行包括 n 个整数 a1, a2, ..., an 表示第 i 件衣服的邮费为 ai 元。 (1 <= n <= 105,1<=ai<=109)
【输出描述】
输出一个整数表示小明所要花费的最小代价。
【输入样例】
5
4 5 3 3 7
【输出样例】
50
import queue
pq = queue.PriorityQueue()
n=int(input())
a=list(map(int,input().split()))
for i in range(len(a)):
pq.put(a[i])
sum=0
while pq.qsize()>1:
t = pq.get()+ pq.get()
sum += t
pq.put(t)
print(sum)
5
4 5 3 3 7
50
>>>
二、栈
【栈(stack)】
- “先进后出”
- 只有唯一的一个出入口,既从这个口进入,又从这个口出来,这是和队列最大的区别。
- 队列有两个口,一个入口和一个出口。
1、用 list 实现栈
st=[]
st.append('hello') # 送入栈,功能是 push()
st.append('world')
st.append(453)
print(st)
print(len(st)) # 栈的长度
print(st[len(st)-1]) # 打印栈顶,功能是top()
print(st[-1]) # 打印栈顶,功能是top()
print(st.pop()) # 弹出栈顶
print(st.pop()) # 弹出栈顶
print(st.pop()) # 弹出栈顶
print(st)
if st:
print("Not Empty") # 是否为空,功能是empty()
else:
print("Empty") # Empty
2、用 collections.deque 实现栈
from collections import deque
st=deque()
st.append('hello') # 送入栈,功能是 push()
st.append('world')
st.append(453)
print(st)
print(len(st)) # 栈的长度
print(st[len(st)-1]) # 打印栈顶,功能是top()
print(st[-1]) # 打印栈顶,功能是top()
print(st.pop()) # 弹出栈顶
print(st.pop()) # 弹出栈顶
print(st.pop()) # 弹出栈顶
print(st) # deque([])
if st:
print("Not Empty") # 是否为空,功能是empty()
else:
print("Empty") # Empty
3、用 queue.LifoQueue 实现栈
Lifo:last in first out,后进先出,就是栈
from queue import LifoQueue
st=LifoQueue(maxsize=100)
st.put('hello')
st.put('world')
st.put(453)
print(st.qsize()) #栈的长度 3
print(st.get()) #弹出栈顶 453
print(st.get()) #弹出栈顶 world
print(st.get()) #弹出栈顶 hello
print(st.empty()) #是否为空 True
4、例题(lanqiaoOJ题号2117)
【题目描述】
小明砍竹子,他面前有 n 棵竹子排成一排,一开始第 i 棵竹子的高度为 hi。他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为H,那么使用一次魔法可以把这一段竹子的高度都变为?,其中?表示对x向下取整。小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为 1。
【输入描述】
第一行为一个正整数 n,表示竹子的棵数。第二行共 n 个空格分开的正整数 hi,表示每棵竹子的高度。
【输出描述】
一个整数表示答案。
【输入样例】
6
2 1 4 2 6 7
【输出样例】
5
(1)暴力法
- 从第一棵竹子开始,从头到尾,找到相同高度的竹子,砍掉这一段竹子。循环做这个操作,直到所有高度都变为 1。
- 复杂度:从左到右遍历一次 O(n),可能遍历很多轮,总复杂度大于 O(n^2)。只能通过 20% 的测试。
from math import *
n=int(input())
a=list(map(int,input().split()))
ans=0
while True:
idx=0
for i in range(n):
if a[i]>a[idx]:
idx=i
if a[idx]==1:
break # 全部高度都是1
val=a[idx]
for i in range(idx,n):
if a[i]!=val:
break
a[i]=floor(sqrt(floor(a[i]/2)+1)) # floor() 向下取整
ans+=1
print(ans)
(2)栈
- 首先计算最多砍多少刀,计算每棵竹子砍到 1 需要多少刀,所有竹子砍数相加得到一个总数,记为ans;
- 记录每棵竹子每次被砍后的新高度;
- 比较任意两个相邻的竹子,它们是否有相同的高度,如果有相同的高度,这两棵竹子接下来可以一起砍,从而少砍一刀,ans减一;
- 比较结束后,ans 就是答案。
from math import *
f=[[0]*10 for _ in range(200010)]
stk=[0]*10
n=int(input())
a=list(map(int,input().split()))
ans=0
for i in range(n):
x=a[i]
top=0
while x>1:
top+=1
stk[top]=x
x=floor(sqrt(floor(x/2)+1))
ans+=top
k=top
j=0
while k>0:
f[i][j]=stk[k]
k-=1
j+=1
for j in range(10):
for i in range(1,n):
if f[i][j]>0 and f[i][j]==f[i-1][j]:
ans-=1
print(ans)
- f[ ][ ] 记录每棵竹子被砍后的高度,f[ i ][ j ] 记录第 i 棵竹子被砍后的高度,f [ i ][ 0 ] 是砍最后一刀后的高度,f[ i ][ top ]是第一次被砍后的高度。
- 用手写栈 stk[ ] 记录砍每刀后的高度,然后赋值给 f[ i ][ ]。比较任意两棵相邻竹子的高度,如果有某个高度相等,可以一起砍,从而少砍一刀。
- 代码的复杂度:两个 for 循环计算 M×n = 10×n 次,是 O(n) 的。总复杂度为 O(n)。
以上,基础数据结构——队列和栈
祝好