数据结构与算法——队列(python版附带详细例子)


author:xiao黄
缓慢而坚定的生长


单向队列

队列也是一种基本的数据结构,在队列中的插入和删除都遵循先进先出(First in First out, FIFO)的原则。元素可以在任何时刻进行插入,但是只有在队列最前面的元素才能被删除。
通常将队列中允许插入的一端称为队尾,将允许删除的一端称为队头。

队列的抽象数据类型

对于队列Q而言,有下面的一些基本的方法:

  • Q.enqueue(x):向队列Q的队尾添加一个元素;
  • Q.dequeue():从队列Q中移除并返回第一个元素,如果队列为空,则触发一个错误;
  • Q.first():返回队列Q中的第一个元素,但并不删除该元素,如果队列为空,则触发一个错误;
  • Q.len():返回队列Q中元素的数量;
  • Q.isEmpty():如果队列Q没有包含任何元素,则返回"True",否则返回"False"。

下面用一个表格来讲解一下队列的基本操作:
在这里插入图片描述

基于数组的队列实现

通过使用python列表来实现一个队列。
先上简化版的队列代码:

class ArrayQueue:
    # 创建一个先入先出的队列

    def __init__(self):
        # 创建一个空队列
        self._items = []
    
    def isEmpty(self):
        # 如果队列为空则返回'True'
        return len(self._items) == 0
    
    def enqueue(self, x):
        # 向队列尾部添加元素x
        self._items.insert(0,x)

    def dequeue(self):
        # 移除第一个元素并返回
        # 如果队列为空,则触发一个错误
        if self.isEmpty():
            raise Exception('Queue is empty')
        return self._items.pop()
    
    def len(self):
        # 返回队列中元素的数量
        return len(self._items)

    def first(self):
        # 返回队列中第一个元素,但并不移除
        # 如果队列为空,则触发一个错误
        if self.isEmpty():
            raise Exception('Queue is empty')
        return self._items[-1]

下面介绍一个较为复杂一点的版本,代码如下:

  • self._data:指一个固定容量的列表实例;
  • self._size:整数,代表当前存储在队列中元素的数量;
  • self._front:整数,代表实例队列中第一个元素的索引;
class ArrayQueue:
    # 创建一个先入先出的队列
    DEFAULT_CAPACITY = 10 # 新队列的初始容量

    def __init__(self):
        # 创建一个空队列
        self._data = [None] * ArrayQueue.DEFAULT_CAPACITY
        self._size = 0
        self._front = 0
    
    def isEmpty(self):
        # 如果队列为空则返回'True'
        return self._size == 0
    
    def enqueue(self, x):
        # 向队列尾部添加元素x
        if self._size == len(self._data):
            self._resize(2 * len(self._data))
        avail = (self._front + self._size) % len(self._data)
        self._data[avail] = x
        self._size += 1

    def dequeue(self):
        # 移除第一个元素并返回
        # 如果队列为空,则触发一个错误
        if self.isEmpty():
            raise Exception('Queue is empty')
        answer = self._data[self._front]
        self._data[self._front] = None
        self._front = (self._front + 1 ) % len(self._data)
        self._size -= 1
        return answer
    
    def len(self):
        # 返回队列中元素的数量
        return self._size

    def first(self):
        # 返回队列中第一个元素,但并不移除
        # 如果队列为空,则触发一个错误
        if self.isEmpty():
            raise Exception('Queue is empty')
        return self._data[self._front]
    
    def _resize(self,cap):
        # 改变列表的容量
        old = self._data
        self._data = [None] * cap
        walk = self._front
        for i in range(self._size):
            self._data[i] = old[walk]
            walk = (1+walk) % len(old)
        self._front = 0

添加和删除元素:
利用下面的公式计算下一个插入的位置:

avail = (self._front + self._size) % len(self._data)

因为有可能当前队列的长度为3,且第一个元素所在的索引为5,在这个队列中已有的3个元素存储位置即为索引5、6和7,故新的元素应该被放置在8的位置。
当调用dequeue操作时,self._front的当前值指明要被删除,利用一个本地变量answer存储当前要删除的值,并且设self._data[self._front]=None。然后更新self._front和self._size,最后返回要删除的值。

例子-约瑟夫问题(单向队列实现)

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
代码如下:

def fun(n,m):
    s = ArrayQueue()
    for i in range(1,n+1):
        s.enqueue(i) # 先把全部入队
    while s.len() > 1:
        for i in range(1,m):
            s.enqueue(s.dequeue()) # 不是第m个继续入队
        print(s.dequeue()) # 第m个就出队
    return s.dequeue()

运行结果如下:
在这里插入图片描述

双端队列

双端队列(double-ended queue 或者deque)支持在队列的头部和尾部进行插入的删除操作。
双端队列D的一些基本方法:

  • D.add_first(x):向双端队列的前面添加一个元素x;
  • D.add_last(x):向双端队列的后面添加一个元素x;
  • D.delete_first():从双端队列中移除并返回第一个元素,如果队列为空,则触发一个错误;
  • D.delete_last():从双端队列中移除并返回最后一个元素,如果队列为空,则触发一个错误;
  • D.first():返回(但不移除)双端队列的第一个元素,如果队列为空,则触发一个错误;
  • D.last():返回(但不移除)双端队列的最后一个元素,如果双端队列为空,则触发一个错误;
  • D.isEmpty():如果双端队列不包含任何一个元素,则返回’True’,否则返回’Fasle’;
  • D.len():返回当前双端队列中的元素个数。

下面通过一个表格来讲解一下双端队列:
在这里插入图片描述

详细代码如下:

class Deque:
    # 创建一个双端队列对象
    def __init__(self):
        # 创建一个双端队列
        self.items = []

    def isEmpty(self):
        # 双端队列是否为空
        return self.items == []

    def add_first(self,x):
        # 在双端队列头部添加元素
        self.items.append(x)

    def add_last(self,x):
        # 在双端队列尾部添加元素
        self.items.insert(0,x)
    
    def delete_first(self):
        # 删除双端队列头部的元素并返回
        # 如果双端队列为空,则触发一个错误
        if self.isEmpty:
            raise Exception('Deque is empty')
        return self.items.pop()

    def delete_last(self):
        # 删除双端队列尾部的元素并返回
        # 如果双端队列为空,则触发一个错误
        if self.isEmpty:
            raise Exception('Deque is empty')
        return self.items.pop(0)
    
    def len(self):
        # 返回双端队列的元素的数量
        return len(self.items)
    
    def first(self):
        # 返回但不移除双端队列的第一个元素
        # 如果双端队列为空,则触发一个错误
        if self.isEmpty:
            raise Exception('Deque is Empty')
        return self.items[-1]
    
    def last(self):
        # 返回但不移除双端队列的最后一个元素
        # 如果双端队列为空,则触发一个错误
        if self.isEmpty:
            raise Exception('Deque is empty')
        return self.items[0]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiao黄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值