5.数据结构---队列
分类:
数据结构
一、队列
1.队列类型
- FIFO:先进先出
- LIFO:后进先出(等同于栈)
- 优先级队列
- 双端队列:LIFO和FIFO结合,可以从队首和队尾添加和删除元素
- 循环队列:队首和队尾相连(可用来解决假溢出)
2.Python自带Queue模块【线程不安全,需加锁】
支持三种队列类型:
- FIFO(queue.queue)
- LIFO(queue.LifoQueue)
- 优先级队列(queue.PriorityQueue)【优先级队列越低越先出来】【堆】
FIFO: import queue 创建一个队列长度为 10 的对象:q = queue.queue(maxsize = 10 ) 队尾插入数据x:q.put(x) 队首删除数据:q.get(),并返回该数据 返回队列的大小:q.qsize() 判断队列是否为空:q.empty(),若为空则返回 True ,反之则FALSE 判断是否为满:q.full与maxsize相呼应 |
3.Python自带Deque模块【线程安全,因为GIL】
支持双端队列
( 1 )新建一个deque对象:q = deque( 'abcdefgh' ),或者创建一个大小为 5 的队列q = deque( 5 ) ( 1 )q.appendleft(x):在列表左侧插入【O( 1 )】 ( 2 )q.popleft():弹出列表左侧的值【O( 1 )】 ( 3 )extendleft:在左侧扩展【O(k)】 ( 4 )q.append(x):在列表右侧插入【O( 1 )】 ( 5 )q.pop():弹出列表右侧的值【O( 1 )】 ( 6 )extend:在右侧扩展【O(k)】 ( 7 )q.rotate( - n):将左端的n个元素移动到右端【O(k)】 q.rotate(n):将右端的n个元素移动到左端 q = deque( 'abcdef' ) q.rotate( - 2 ) print (q) / / deque([ 'c' , 'd' , 'e' , 'f' , 'a' , 'b' ]) q.rotate( 2 ) print (q) / / deque([ 'e' , 'f' , 'a' , 'b' , 'c' , 'd' ]) ( 8 )q.remove( 'c' ):删除一个指定元素【O(n)】 ( 9 )q.clear():清空链表所有元素,使其长度为 0 ( 10 )q.reverse():将队列反转 ( 11 )q.count(x):返回q中x的数量 ( 12 ) len (q):返回q的长度 |
4.循环队列
队尾出来进队首,双端队列的rotate可以实现循环队列。
二、算法
1.两个队列实现栈
题目:使用队列实现栈的下列操作:
push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空
思路:
插入:直接在非空的queue中添加新元素
删除:将一个非空的queue中的数依次从队首到队尾放入空的queue中,直到只剩下一个数,将最后一个数弹出。
class MyQueue ( object ): def __init__( self ): self .stack1 = [] self .stack2 = [] def push( self , x): self .stack1.append(x) def pop( self ): if self .stack2 ! = []: # 栈2不为空 self .stack2.pop() elif self .stack2 = = [] and self .stack1 ! = []: while self .stack1 ! = []: tmp = self .stack1[ - 1 ] self .stack1.pop() self .stack2.append(tmp) self .stack2.pop() else : # 栈2为空,栈1为空 print ( 'query is empty' ) def top( self ): return self .stack1[ - 1 ] def empty( self ): if len ( self .stack1) = = 0 and len ( self .stack2) = = 0 : return True else : return False queue = MyQueue() queue.push( 1 ) queue.push( 2 ) queue.pop() queue.push( 3 ) print (queue) |
2.两个栈实现队列
题目:使用栈实现队列的下列操作:
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
思路:
插入:在stack1中添加新元素
删除:删除元素前,先判断stack2是否为空,如果不为空,直接弹出stack2;否则,将stack1中的所有元素全部放入stack2中,再弹出栈顶元素
class MyQueue( object ): def __init__( self ): self .queue1 = [] self .queue2 = [] def push( self , x): if len ( self .queue2) = = 0 : self .queue1.append(x) if len ( self .queue1) = = 0 : self .queue2.append(x) def pop( self ): # 将queue的数放入另一个queue中,然后将当前queue里面的数一个个放入另一个queue,直到当前queue的长度为1时,删除当前queue最后一个数 if len ( self .queue1) ! = 0 and len ( self .queue2) = = 0 : while len ( self .queue1) ! = 1 : tmp = self .queue1[ - 1 ] self .queue1.pop() self .queue2.append(tmp) else : while len ( self .queue2) ! = 1 : tmp = self .queue2[ - 1 ] self .queue2.pop() self .queue1.append(tmp) def peek( self ): if len ( self .queue1) = = 0 : return self .queue2[ - 1 ] else : return self .queue1[ - 1 ] def empty( self ): if len ( self .queue1) = = 0 and len ( self .queue2) = = 0 : return True else : return False Queue = MyQueue() Queue.push( 1 ) Queue.push( 2 ) print (Queue.peek()) Queue.pop() print (Queue) |
3.报数淘汰
''' 下面的例子是用queue中的FIFO实现一个功能,6个人传土豆,每数到7就淘汰手中有土豆的人,直到最后只剩一个人。 ''' # 循环队列,num一定要比人数多 import queue def hotpotato(namelist,num): que = queue.Queue( len (namelist)) for name in namelist: que.put(name) while que.qsize()> 1 : for item in range (num - 1 ): que.put(que.get()) # put队尾插入,get队首删除 que.get() return que.get() namelist = [ 'a' , 'b' , 'c' , 'd' , 'e' ] print (hotpotato(namelist, 7 )) |
参考文献:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现