广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python数据结构之队列详解
  • 139
分享到

Python数据结构之队列详解

2024-04-02 19:04:59 139人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录0. 学习目标1. 队列的基本概念1.1 队列的基本概念1.2 队列抽象数据类型1.3 队列的应用场景2. 队列的实现2.1 顺序队列的实现2.2 链队列的实现2.3 队列的不同

0. 学习目标

栈和队列是在程序设计中常见的数据类型,从数据结构的角度来讲,栈和队列也是线性表,是操作受限的线性表,它们的基本操作是线性表操作的子集,但从数据类型的角度来讲,它们与线性表又有着巨大的不同。本节将介绍队列的定义及其不同实现,并且给出队列的一些实际应用。
通过本节学习,应掌握以下内容:

  • 队列的基本概念及不同实现方法
  • 队列基本操作的实现及时间复杂度
  • 利用队列的基本操作实现复杂算法

1. 队列的基本概念

1.1 队列的基本概念

队列 (Queue) 是插入和删除操作分别被限制在序列两端的线性表(新元素从一段插入其中,则只能从另一端删除已有元素),对于队列而言,允许插入元素的一端称为队尾 (rear),而允许取出元素的一段则称为队头 (front)。

在队列中,数据到达的顺序很重要。最新添加的元素位于必须在队尾,在队列中时间最长的元素则排在最前面,这种排序原则被称作先进先出 (first in first out,FIFO),或后进后出 (last in first out, LILO)。

队列在现实中的例子随处可见,我们生活中就餐所需要进行的排队就是一个队列的现实例子,最早进入队列的人可以首先就餐,而后来者需要排于队尾等待。假设队列为 Q=(a0,a1,...,an),则队头元素为a0,an为队尾元素,队列中元素按a0,a1,...,an的顺序入队 (enqueue),出队 (dequeue) 也只能按照这个顺序依次退出,队头元素是第一个出队 (dequeue) 的元素,而只有a0,a1,...,an-1在都出队后,才an 能退出队列。下图是一个简单的队列示例:

通过观察元素的添加和移除顺序,就可以快速理解队列所蕴含的思想。下图展示了队列元素的入队和出队过程,队列中元素的插入顺序和移除顺序是完全相同的。

1.2 队列抽象数据类型

除了主要的操作(入队和出队)外,队列还具有初始化、判队空和求队长度等辅助操作。具体而言,队列的抽象数据类型定义如下:

1.3 队列的应用场景

队列具有广泛的应用场景,例如:

  • 在作业具有相同优先级的前提下,操作系统会按照作业的到达顺序安排作业;
  • 击键操作被放入一个类似于队列的缓冲区,以便对应的字符按正确的顺序显示;
  • 模拟现实世界的队列;
  • 多道程序设计;
  • 异步数据传输;

除了以上应用外,我们在之后的学习中还将看到队列用作许多算法的辅助数据结构。

2. 队列的实现

和线性表一样,队列同样有顺序存储和链式存储两种存储表示方式。

2.1 顺序队列的实现

类似于顺序栈,队列的顺序存储结构利用一组地址连续的存储单元依次存放从队列头到队列尾依次存放,同时需要用两个指针 front 和 rear 分别指示队列头元素和队列尾元素的位置。初始化空队列时,front=rear=0,当元素入队时,rear 加 1,而元素出队时,front 加 1,如下所示:

从以上示例中,可以很清楚地看到位于队头之前的空间被浪费了,为了解决这一问题,我们可以假设顺序队列为环状空间,将最后一个元素和第一个元素视为连续的,如下图所示:

从上图可以看出,当队列满时与队列空时,都有front=rear,因此无法通过 front==rear 来判断队列是否已满。针对这一问题,有两种解决方法:1) 设置标志来指示队列中是否还有空闲空间;2) 放弃一个元素空间,即当 front 指针在 rear 指针的下一位时 ((rear+1)%max_size=front) 队列为满。以下实现使用第二种方案。

同样顺序队列可以是固定长度和动态长度,当队列满时,定长顺序队列会抛出栈满异常,动态顺序队列则会动态申请空闲空间。

2.1.1 队列的初始化

顺序队列的初始化需要 4 部分信息:queue 列表用于存储数据元素,max_size 用于存储 queue 列表的最大长度,以及 front 和 rear 分别用于记录队头元素和队尾元素的索引

class Queue:
    def __init__(self, max_size=5):
        self.max_size = max_size
        self.queue = [None] * self.max_size
        self.front = 0
        self.rear = 0

2.1.2 求队列长度

由于 front 和 rear 分别用于记录队头元素和队尾元素的索引,因此我们可以方便的计算出队列的长度;同时我们需要考虑队列为循环队列,front 可能大于 rear,不能直接通过 rear-front,我们需要利用公式计算解决此问题:

python 实现如下:

    def size(self):
        return (self.rear-self.front+self.max_size) % self.max_size

2.1.3 判队列空

根据 front 和 rear 的值可以方便的判断队列是否为空:

    def isempty(self):
        return self.rear==self.front

2.1.4 判队列满

根据 front 和 rear 的值可以方便的判断队列是否还有空余空间:

    def isfull(self):
        return ((self.rear+1) % self.max_size == self.front)

2.1.5 入队

入队时,需要首先判断队列中是否还有空闲空间,然后根据队列为定长顺序队列或动态顺序队列,入队操作稍有不同:

[定长顺序队列的入队操作] 如果队满,则引发异常:

    def enqueue(self, data):
        if not self.isfull():
            self.queue[self.rear] = data
            self.rear = (self.rear+1) % self.max_size
        else:
            raise IndexError("Full Queue Exception")

[动态顺序队列的入队操作] 如果队列满,则首先申请新空间,然后再执行入队操作:

    def resize(self):
        new_size = 2 * self.max_size
        new_queue = [None] * new_size
        for i in range(self.max_size):
            new_queue[i] = self.queue[i]
        self.queue = new_queue
        self.max_size = new_size

    def enqueue(self, data):
        if self.isfull():
            self.resize()
        self.queue[self.rear] = data
        self.rear = (self.rear+1) % self.max_size

入队的时间复杂度为O(1)。这里需要注意的是,虽然当动态顺序队列满时,原队列中的元素需要首先复制到新队列中,然后添加新元素,但参考《顺序表及其操作实现》中顺序表追加操作的介绍,由于 n 次入队操作的总时间T(n) 与)O(n) 成正比,因此队栈的摊销时间复杂度可以认为是O(1)。

2.1.6 出队

若队列不空,则删除并返回队头元素:

    def dequeue(self):
        if not self.isempty():
            result = self.queue[self.front]
            self.front = (self.front+1) % self.max_size
            return result
        else:
            raise IndexError("Empty Queue Exception")

2.1.7 求队头元素

若队列不空,则返回队头元素:

    def head(self):
        if not self.isempty():
            result = self.queue[self.front]
            return result
        else:
            raise IndexError("Empty Queue Exception")

2.2 链队列的实现

队列的另一种存储表示方式是使用链式存储结构,因此也常称为链队列,其中 enqueue 操作是通过在链表尾部插入元素来实现的,dequeue 操作是通过从头部删除节点来实现的。

2.2.1 队列结点

队列的结点实现与链表并无差别:

class node:
    def __init__(self, data=None):
        self.data = data
        self.next = None
    def __str__(self):
        return str(self.data)

2.2.2 队列的初始化

队列的初始化函数中,使其队头指针 front 和 rear 均指向 None,并初始化队列长度:

class Queue:
    def __init__(self):
        self.front = None
        self.rear = None
        self.num = 0

2.2.3 求队列长度

返回 size 的值用于求取队列的长度,如果没有 size 属性,则需要遍历整个链表才能得到队列长度:

    def size(self):
        return self.num

2.2.4 判队列空

根据队列的长度可以很容易的判断队列是否为空队列:

    def isempty(self):
        return self.num <= 0

2.2.5 入队

入队时,在队尾插入新元素,并且需要将队尾指针 rear 指向新元素,如果队列为空,需要将队头指针 front 也指向此元素:

    def enqueue(self, data):
        node = Node(data)
        if self.front is None:
            self.rear = node
            self.front = self.rear
        else:
            self.rear.next = node
            self.rear = node
        self.num += 1

2.2.6 出队

若队列不空,则删除并返回队头元素,并且需要更新队头指针 front 指向原队头结点的后继结点,若出队元素尾队中最后一个结点,则更新队尾指针 rear:

    def dequeue(self):
        if self.isempty():
            raise IndexError("Empty Queue Exception")
        result = self.front.data
        self.front = self.front.next
        self.num -= 1
        if self.isempty():
            self.rear = self.front
        return result

2.2.7 求队头元素

若队列不空,则返回队头元素:

    def head(self):
        if self.isempty():
            raise IndexError("Empty Queue Exception")
        result = self.front.data
        return result

2.3 队列的不同实现对比

队列的不同实现对比与栈的不同实现类似,可以参考《栈及其操作实现》。

3. 队列应用

接下来,我们首先测试上述实现的队列,以验证操作的有效性,然后利用实现的基本操作来解决实际算法问题。

3.1 顺序队列的应用

首先初始化一个顺序队列 queue,然后测试相关操作:

# 初始化一个最大长度为5的队列
q = Queue(5)
print('队列空?', q.isempty())
for i in range(4):
    print('入队元素:', i)
    q.enqueue(i)
print('队列满?', q.isfull())
print('队头元素:', q.head())
print('队列长度为:', q.size())
while not q.isempty():
    print('出队元素:', q.dequeue())

测试程序输出结果如下:

队列空? True
入队元素: 0
入队元素: 1
入队元素: 2
入队元素: 3
# 队列中弃用一个空间,因此队列中有4个元素即满
队列满? True
队头元素: 0
队列长度为: 4
出队元素: 0
出队元素: 1
出队元素: 2
出队元素: 3

3.2 链队列的应用

首先初始化一个链队列 queue,然后测试相关操作:

# 初始化新队列
q = Queue()
print('队列空?', q.isempty())
for i in range(4):
    print('入队元素:', i)
    q.enqueue(i)
print('队头元素:', q.head())
print('队列长度为:', q.size())
while not q.isempty():
    print('出队元素:', q.dequeue())

测试程序输出结果如下:

队列空? True
入队元素: 0
入队元素: 1
入队元素: 2
入队元素: 3
队头元素: 0
队列长度为: 4
出队元素: 0
出队元素: 1
出队元素: 2
出队元素: 3

3.3 利用队列基本操作实现复杂算法

考虑经典的约瑟夫斯环问题,n 个人围成一圈,从第 1 个人开始报数,第 m 个将被淘汰,重复上述过程,直到只剩下一个人,其余人都将被淘汰。

我们使用队列来模拟一个环,如下图所示,从队列的头部开始,将位于队首的人移出队列并立刻将其插入队列的尾部,之后此人会一直等待,直到其再次到达队列的头部。在出列和入列 m-1 次之后,位于队列头部的人出局(即第 m 个人),然后新一轮游戏开始;如此反复,直到队列中只剩下一个人(队列的大小为 1 )。

def Josephus(name_list, m):
    queue = Queue()
    for name in name_list:
        queue.enqueue(name)
    while queue.size() > 1:
        for i in range(m-1):
            queue.enqueue(queue.dequeue())
        queue.dequeue()
    return queue.head()
# n=6, m=5
result = Josephus(["A", "B", "C", "D", "E", "F"], 5)
print('幸存的人为', result)

程序输出结果如下:

幸存的人为 A

以上就是Python数据结构之队列详解的详细内容,更多关于Python队列的资料请关注编程网其它相关文章!

--结束END--

本文标题: Python数据结构之队列详解

本文链接: https://www.lsjlt.com/news/143217.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python数据结构之队列详解
    目录0. 学习目标1. 队列的基本概念1.1 队列的基本概念1.2 队列抽象数据类型1.3 队列的应用场景2. 队列的实现2.1 顺序队列的实现2.2 链队列的实现2.3 队列的不同...
    99+
    2022-11-13
  • 详解python数据结构之队列Queue
    目录一、前言二、Queue的基本格式三、入队列函数 en_queue四、删除数据函数 de_queue一、前言 队列Queue是一种先进先出(FIFO,First In First ...
    99+
    2022-11-12
  • JS数据结构之队列结构详解
    目录一.认识队列二.队列的应用三.队列类的创建四.队列的常见操作五.击鼓传花六.优先级队列七.优先级队列的实现一.认识队列 受限的线性结构: 我们已经学习了一种受限的线性结构:栈结构...
    99+
    2022-11-13
    JS队列结构 JS队列 JS 数据结构
  • Java 数据结构之队列(Queue)详解
    目录 1、在Java中有哪些常见的队列? 2、Queue 接口分析 3、Deque 接口分析 4、PriorityQueue 的实现原理详解 5、使用Java数组实现队列的简单示例 1、在Java中有哪些常见的队列?         在...
    99+
    2023-10-12
    java 队列 Queue 接口 Deque 接口
  • 数据结构TypeScript之栈和队列详解
    目录栈结构特点出栈和入栈面向对象方法封装栈队列结构特点出队和入队面向对象方法封装队列栈结构特点 栈是线性表的其中一种,用于存储固定顺序的元素,元素增删具有先进后出的特点。 出栈和入...
    99+
    2023-01-30
    TypeScript数据结构栈队列 TypeScript数据结构
  • Javascript数据结构之栈和队列详解
    目录前言栈(stack)栈实现解决实际问题栈的另外应用简单队列(Queue)队列实现队列应用 - 树的广度优先搜索(breadth-first search,BFS)优先队列优先队列...
    99+
    2022-11-13
  • JavaScript队列数据结构详解
    目录什么是队列?JavaScript中的队列JavaScript中的应用场景最近的请求次数补充总结写在前面: 在上一篇文章中介绍了栈这个数据结构,这篇文章介绍一下队列。 什么是队列?...
    99+
    2022-11-13
  • python数据结构之栈、队列及双端队列
    目录1.线性数据结构的定义2.栈2.1栈的定义2.2栈的数据类型2.3用python实现栈2.4栈的应用3.队列3.1队列的定义3.2队列抽象数据类型3.3用python实现队列3....
    99+
    2022-11-12
  • Java数据结构之堆(优先队列)详解
    目录堆的性质堆的分类堆的向下调整堆的建立堆得向上调整堆的常用操作入队列出队列获取队首元素TopK 问题例子数组排序堆的性质 堆逻辑上是一棵完全二叉树,堆物理上是保存在数组中 。 总...
    99+
    2022-11-13
  • Python数据结构之优先级队列queue用法详解
    目录一、基本用法二、LIFO队列三、优先队列一、基本用法 Queue类实现了一个基本的先进先出容器。使用put()将元素增加到这个序列的一端,使用get()从另一端删除。具体代码如下...
    99+
    2022-11-12
  • C++数据结构的队列详解
    目录前言1.队列的概念及结构2.队列的实现2.1queue.h2.2queue.c2.3test.c总结前言 hello,大家好,这期文章我们来分享数据结构关于队列的知识。希望对大家...
    99+
    2022-11-12
  • Java数据结构之栈与队列实例详解
    目录一,栈1,概念2,栈的操作3,栈的实现 4,实现mystack二,队列1,概念 2,队列的实现 3,实现myqueue栈、队列与数组的区别?总结 一,栈 1,概念 在我们软件应用...
    99+
    2022-11-12
  • C语言数据结构之队列算法详解
    目录一、前言二、基本概念三、顺序队列四、链队列五、循环队列六、总结与提高一、前言 队列在程序设计中经常出现,如:操作系统中的排队问题。 这篇文章主要介绍了队列的...
    99+
    2022-11-12
  • Python 数据结构之队列的实现
    Python 队列 Queue 队列是一种先进先出(FIFO)的数据类型, 新的元素通过 入队 的方式添加进 Queue 的末尾, 出队 就是从 Queue 的头部删除元素. 用列表来做 Queue: ...
    99+
    2022-06-04
    数据结构 队列 Python
  • 用Python实现数据结构之队列
    队列与栈的类型很相似,但它遵循的原则是先进先出(FIFO),也就是元素插入的时候只能在该数据结构的末端,而删除只能删除最前面的元素。队列同样应用广泛,例如打印机的队列或者是一个web服务器响应请求。 关于队列的方法 作为一个队列,同样...
    99+
    2023-01-30
    数据结构 队列 Python
  • 数据结构之——Python实现循环队列
    栈是先入后出,与之相反的是队列,队列是先进先出的线性结构。队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。 图1 队列的定义 队列的存储结构中使用的最多的是循...
    99+
    2023-01-31
    数据结构 队列 Python
  • Java深入了解数据结构之栈与队列的详解
    目录一,栈1,概念2,栈的操作3,栈的实现①入栈②出栈③获取栈顶元素④判断栈是否为空 4,实现mystack二,队列1,概念2,队列的实现①入队②出队③获取队首元素3,实现...
    99+
    2022-11-13
  • Java数据结构之优先级队列(堆)图文详解
    目录一、堆的概念二、向下调整1.建初堆2.建堆三、优先级队列1.什么是优先队列?2.入队列3.出队列4.返回队首元素5.堆的其他TopK问题总结:总结一、堆的概念 堆的定义:n个元素...
    99+
    2022-11-13
  • c语言数据结构之栈和队列详解(Stack&Queue)
    目录简介栈一、栈的基本概念1、栈的定义2、栈的常见基本操作二、栈的顺序存储结构1、栈的顺序存储2、顺序栈的基本算法3、共享栈(两栈共享空间)三、栈的链式存储结构1、链栈2、链栈的基本...
    99+
    2022-11-13
  • Java数据结构之优先级队列(PriorityQueue)用法详解
    目录概念PriorityQueue的使用小试牛刀(最小k个数) 堆的介绍优先级队列的模拟实现Top-k问题概念 优先级队列是一种先进先出(FIFO)的数据结构,与队列不同的...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作