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))
参考文献: