栈队列
Posted guoxing-z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了栈队列相关的知识,希望对你有一定的参考价值。
栈、队列
栈
-
特性:先进后出
-
栈顶,栈底
- 从栈顶向栈底添加元素,从栈顶取元素
-
应用:每个 web 浏览器都有一个返回按钮。当你浏览网页时,这些网页被放置在一个栈中(实际是网页的网址)。你现在查看的网页在顶部,你第一个查看的网页在底部。如果按‘返回’按钮,将按相反的顺序浏览刚才的页面。
-
模型:
- 栈需要实现的方法:
- Stack() 创建一个空的新栈。 它不需要参数,并返回一个空栈。
- push(item)将一个新项添加到栈的顶部。它需要 item 做参数并不返回任何内容。
- pop() 从栈中删除顶部项。它不需要参数并返回 item 。栈被修改。
- peek() 从栈返回顶部项,但不会删除它。不需要参数。 不修改栈。
- isEmpty() 测试栈是否为空。不需要参数,并返回布尔值。
- size() 返回栈中的 item 数量。不需要参数,并返回一个整数。
定义:
class Stack(object):
def __init__(self):
"""由上图可以看出,栈底部就是列表头部,栈顶部就是列表尾部"""
self.items = []
def size(self):
return len(self.items)
def isEmpty(self):
return self.items == []
def push(self,item):
"""添加时从顶部添加,即添加到列表末尾"""
self.items.append(item)
def pop(self):
"""删除顶部的,即列表末尾的"""
return self.items.pop()
def peek(self):
"""返回栈顶部元素的索引"""
return len(self.items) - 1
使用:
ss = Stack()
ss.push(1)
ss.push(2)
ss.push(3)
print(‘-----‘)
print(ss.size())
print(ss.isEmpty())
print(ss.peek())
print(‘-----‘)
print(ss.pop())
print(ss.pop())
print(ss.pop()) # 结果正确,先进后出
结果:
-----
3
False
2
-----
3
2
1
队列
- 队列:先进先出
- 应用场景:
- 我们的计算机实验室有 30 台计算机与一台打印机联网。当学生想要打印时,他们的打印任务与正在等待的所有其他打印任务“一致”。第一个进入的任务是先完成。如果你是最后一个,你必须等待你前面的所有其他任务打印
- 模型:
- 队列内部需要实现的方法:
- Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
- enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
- dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。
- isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
- size() 返回队列中的项数。它不需要参数,并返回一个整数。
定义:
import json
class Queue(object):
def __init__(self):
self.items = []
def size(self):
return len(self.items)
def isEmpty(self):
return self.items == []
def enqueue(self,item):
self.items.append(item)
def dequeue(self):
return self.items.pop(0)
def __str__(self):
return json.dumps(self.items)
使用:
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
print(q.dequeue())
print(q.dequeue())
print(q.dequeue())
结果:
1
2
3
案例:烫手的山芋
-
规则:
- 烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。
-
分析:
- 在一轮游戏中山芋会被传递6次(注意:第7秒时没有进行传递)
- 山芋传递的次数不受孩子个数的影响
- 山芋传递六次后一轮游戏结束,淘汰一个孩子游戏继续
- 队列:先进先出,只可以从对头取元素,从队尾添加元素。
- 准则:保证队头孩子手里面有山芋(谁手里有山芋谁作为队头)
- 方便删除元素。最终7秒到的时候需要将手里有山芋的孩子从队列中剔除。
使用:
q = Queue() # 还是上面队列的定义
kids = [‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘]
# 将6个孩子添加到了队列中
for kid in kids:
q.enqueue(kid)
while q.size() >= 2:
for num in range(6):
item = q.dequeue()
q.enqueue(item)
q.dequeue()
print(‘玩家情况:‘,q)
结果:
玩家情况: ["B", "C", "D", "E", "F"]
玩家情况: ["D", "E", "F", "B"]
玩家情况: ["B", "D", "E"]
玩家情况: ["D", "E"]
玩家情况: ["E"]
双端队列
-
特性:
- 同队列相比,有两个头部和尾部。可以在双端进行数据的插入和删除,提供了单数据结构中栈和队列的特性
-
双端队列需要实现的方法:
- Deque() 创建一个空的新 deque。它不需要参数,并返回空的 deque。
- addFront(item) 将一个新项添加到 deque 的首部。它需要 item 参数 并不返回任何内容。
- addRear(item) 将一个新项添加到 deque 的尾部。它需要 item 参数并不返回任何内容。
- removeFront() 从 deque 中删除首项。它不需要参数并返回 item。deque 被修改。
- removeRear() 从 deque 中删除尾项。它不需要参数并返回 item。deque 被修改。
- isEmpty() 测试 deque 是否为空。它不需要参数,并返回布尔值。
- size() 返回 deque 中的项数。它不需要参数,并返回一个整数。
-
双端队列应用案例:回文检查
- 回文是一个字符串,读取首尾相同的字符,例如,radar toot madam。
定义:
import json
class Deque(object):
def __init__(self):
self.items = []
def addFront(self,item):
self.items.insert(0,item)
def addRear(self,item):
self.items.append(item)
def removeFront(self):
return self.items.pop(0)
def removeRear(self):
return self.items.pop()
def isEmpty(self):
return self.items == []
def size(self):
return len(self.items)
def __str__(self):
return json.dumps(self.items)
测试:
dq = Deque()
dq.addFront(1)
dq.addFront(2)
dq.addFront(3) # [3,2,1]
dq.addRear(4)
dq.addRear(5)
dq.addRear(6) # [3,2,1,4,5,6]
print(‘---‘)
print(dq.isEmpty())
print(dq.size())
print(‘---‘)
print(dq.removeRear())
print(dq.removeFront())
print(dq.removeRear())
print(dq.removeFront())
print(dq.removeRear())
print(dq.removeFront()) # 6,3,5,2,4,1
---
False
6
---
6
3
5
2
4
1
使用:
ss = ‘上海自来水来自海上‘ # 长度为9,上1=0,上2=8
for i in list(ss):
dq.addRear(i)
for i in range(dq.size()//2):
if dq.removeFront() != dq.removeRear():
print(ss,‘不是回文‘)
break
else:
print(ss,‘是回文‘)
结果:
上海自来水来自海上 是回文
面试题
两个队列实现栈、两个栈实现队列
定义:栈
class Stack(object):
"""栈"""
def __init__(self):
"""由上图可以看出,栈底部就是列表头部,栈顶部就是列表尾部"""
self.items = []
def size(self):
return len(self.items)
def isEmpty(self):
return self.items == []
def push(self,item):
"""添加时从顶部添加,即添加到列表末尾"""
self.items.append(item)
def pop(self):
"""删除顶部的,即列表末尾的"""
return self.items.pop()
def peek(self):
"""返回栈顶部元素的索引"""
return len(self.items) - 1
定义:队列
import json
class Queue(object): # 自己写的
"""队列"""
def __init__(self):
self.items = []
def size(self):
return len(self.items)
def isEmpty(self):
return self.items == []
def enqueue(self,item):
self.items.append(item)
def dequeue(self):
return self.items.pop(0)
def __str__(self):
return json.dumps(self.items)
两个队列实现栈
q1 = Queue()
q2 = Queue()
lis = [1,2,3,4,5,6]
for i in lis:
q1.enqueue(i) # 先赋值,[1,2,3,4,5,6]
while q1.size() > 1:
item = q1.dequeue()
q2.enqueue(item) # 将值在两个队列中来回倒置,逐步取出末尾元素
if q1.size() == 1:
print(q1.dequeue())
q1,q2 = q2,q1
print(q1.dequeue()) # 实现了栈特性:先进后出
6
5
4
3
2
1
两个栈实现队列
s1 = Stack()
s2 = Stack()
lis = [1,2,3,4,5,6]
for i in lis:
s1.push(i) # 先赋值,[1,2,3,4,5,6]
for i in range(s1.size()):
item = s1.pop()
s2.push(item) # 迭代删除s1中的末尾元素,并将返回的元素添加到s2中,[6,5,4,3,2,1]
while s2.size():
print(s2.pop()) # 循环删除s2中的末尾元素。结果实现了队列特性:先进先出
1
2
3
4
5
6
测试None的添加
q = []
q.append(None)
q.append(None)
q
[None, None]
if q:
print(1)
1
以上是关于栈队列的主要内容,如果未能解决你的问题,请参考以下文章