栈队列

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

以上是关于栈队列的主要内容,如果未能解决你的问题,请参考以下文章

用两个队列实现一个栈and用两个栈实现一个队列

数据结构栈队列相关代码(数据结构笔试复测Leecode牛客)

数据结构栈与队列

数据结构栈与队列

栈和队列基本操作

代码随想录算法训练营第10天 | ● 理论基础 ● 232.用栈实现队列 ● 225. 用队列实现栈