【ShuQiHere】 深入理解队列的实现方式:数组、链表与循环队列的全面解析

🎓 【ShuQiHere】 🌟

在计算机科学中,队列(Queue) 是一种常见的数据结构,它遵循**先进先出(FIFO, First In First Out)**的原则。无论是任务调度、消息队列、或是操作系统中的任务管理,队列都扮演了至关重要的角色。

今天,我们将深入探讨四种常见的队列实现方式,并通过类比和代码示例帮助大家更好地理解每种实现方式的特点。


📖 目录

  1. 队列的基本概念
  2. 数组实现队列
  3. 链表实现队列
  4. 循环队列
  5. 移动元素的队列实现
  6. 总结

🧠 队列的基本概念

队列是一种遵循**先进先出(FIFO, First In First Out)**原则的线性数据结构。这意味着第一个进入队列的元素将是第一个被移除的元素,类似于现实生活中的排队场景。它通常支持两种操作:

  • 入队(Enqueue):将元素添加到队列末尾。
  • 出队(Dequeue):从队列前端移除元素。

接下来,我们将分别探讨四种常见的队列实现方式,并通过代码和类比帮助你更好地理解它们。


📦 数组实现队列(Array Queue) ☕️

数组实现队列(Array Queue) 是最基本的队列实现方式。它通过一个固定大小的数组来存储元素,并使用两个指针来追踪队列的前端(front)和尾端(rear)。

🎨 形象类比:固定排队窗口

想象一下你在一家咖啡店排队,店内有一排固定的座位,每个顾客只能按照顺序入座,依次从第一个座位开始坐。当一个顾客离开后,虽然座位空出来了,但后面的顾客不会前移,新来的顾客也不能占用前面空出来的座位。这就导致空间浪费——这正是数组实现队列的一个典型问题。

🛠 主要操作:

  • enqueue(入队):在队列末端插入新元素,rear 指针向后移动。
  • dequeue(出队):从队列前端移除元素,front 指针向后移动,但前面的空位不能再被利用。

🌟 优点:

  • 数组结构简单,入队和出队操作时间复杂度均为 (O(1))。

⚠️ 缺点:

  • 队列容量固定,无法动态扩展。
  • 前端空位不能被重用,导致空间浪费。

📝 代码示例:

class ArrayQueue:
    def __init__(self, capacity):
        self.queue = [None] * capacity
        self.capacity = capacity
        self.front = 0
        self.rear = -1
        self.size = 0
    
    def is_empty(self):
        return self.size == 0
    
    def is_full(self):
        return self.size == self.capacity
    
    def enqueue(self, item):
        if self.is_full():
            print("队列已满,无法入队")
            return
        self.rear += 1
        self.queue[self.rear] = item
        self.size += 1
        print(f"元素 {item} 已入队。队列状态:{self.queue}")
    
    def dequeue(self):
        if self.is_empty():
            print("队列为空,无法出队")
            return None
        item = self.queue[self.front]
        self.queue[self.front] = None
        self.front += 1
        self.size -= 1
        print(f"元素 {item} 已出队。队列状态:{self.queue}")
        return item

🚀 小结:

数组实现队列简单高效,但它的固定大小和空间浪费问题使得它在需要频繁入队和出队的场景中并不理想。


🔗 链表实现队列(Linked List Queue) 🏃‍♂️

链表实现队列 是通过链表来动态存储数据,每个节点不仅存储元素,还包含一个指向下一个节点的指针。这种实现方式允许队列根据需要动态增长。

🎨 形象类比:动态排队队伍

想象一条动态的排队队伍,每个顾客都可以自由站在队伍的末尾。即使前面的顾客离开,后面的顾客也会自然向前移动,队伍的长度根据需求不断调整。这种灵活的排队方式正是链表实现队列的特点。

🛠 主要操作:

  • enqueue(入队):在链表末端插入新节点。
  • dequeue(出队):移除链表的头部节点。

🌟 优点:

  • 队列大小不受限制,可以根据需要动态扩展。
  • 没有空间浪费问题。

⚠️ 缺点:

  • 每个节点需要额外的内存来存储指针,增加了内存开销。

📝 代码示例:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedListQueue:
    def __init__(self):
        self.front = None
        self.rear = None
        self.size = 0
    
    def is_empty(self):
        return self.front is None
    
    def enqueue(self, item):
        new_node = Node(item)
        if self.is_empty():
            self.front = self.rear = new_node
        else:
            self.rear.next = new_node
            self.rear = new_node
        self.size += 1
        print(f"元素 {item} 已入队。队列当前长度:{self.size}")
    
    def dequeue(self):
        if self.is_empty():
            print("队列为空,无法出队")
            return None
        item = self.front.data
        self.front = self.front.next
        if self.front is None:
            self.rear = None
        self.size -= 1
        print(f"元素 {item} 已出队。队列当前长度:{self.size}")
        return item

🚀 小结:

链表实现的队列适合需要灵活调整队列大小的场景,避免了数组队列中的空间浪费问题,但额外的指针存储增加了内存开销。


🔄 循环队列(Circular Queue) 🔄

循环队列(Circular Queue) 是一种使用数组实现的队列,但通过取模运算使得数组首尾相连,从而有效利用前端的空位。

🎨 形象类比:环形传送带

想象一个环形传送带,每个顾客都可以在传送带上占据一个位置。当顾客离开时,传送带会继续旋转,新来的顾客可以占据空出来的位置,即使传送带转了一圈,空间仍然可以被重复利用。这种场景类似于循环队列的工作原理。

🛠 主要操作:

  • enqueue(入队):将元素插入队列尾端,rear 通过取模运算实现循环。
  • dequeue(出队):从队列前端移除元素,front 通过取模运算实现循环。

🌟 优点:

  • 可以充分利用数组的空间,不会浪费前端空位。

⚠️ 缺点:

  • 需要处理前端和尾端指针的循环操作,稍微增加了实现复杂性。

📝 代码示例:

class CircularQueue:
    def __init__(self, capacity):
        self.queue = [None] * capacity
        self.capacity = capacity
        self.front = 0
        self.rear = -1
        self.size = 0
    
    def is_empty(self):
        return self.size == 0
    
    def is_full(self):
        return self.size == self.capacity
    
    def enqueue(self, item):
        if self.is_full():
            print("队列已满,无法入队")




            return
        self.rear = (self.rear + 1) % self.capacity
        self.queue[self.rear] = item
        self.size += 1
        print(f"元素 {item} 已入队。队列状态:{self.queue}")
    
    def dequeue(self):
        if self.is_empty():
            print("队列为空,无法出队")
            return None
        item = self.queue[self.front]
        self.queue[self.front] = None
        self.front = (self.front + 1) % self.capacity
        self.size -= 1
        print(f"元素 {item} 已出队。队列状态:{self.queue}")
        return item

🚀 小结:

循环队列能够有效利用数组中的空位,避免空间浪费,适合需要高效空间利用的场景。然而,由于指针需要循环操作,代码的实现复杂性略有提升。


🚛 移动元素的队列实现(Shift Queue) 🚛

移动元素的队列实现(Shift Queue) 是一种特殊的队列实现方式,每次出队时,所有后面的元素都会向前移动一位。这种方式确保队列总是从数组的第一个位置开始,但其性能会因为频繁的元素移动而变得非常低效。

🎨 形象类比:自动前移的队伍

想象一条队伍,每当有顾客离开时,所有后面的顾客都会自动向前移动一位。这种排队方式虽然保证了队伍的整齐,但每次有人离开时,队伍的整体移动都会带来不小的负担。这就类似于移动元素的队列实现方式。

🛠 主要操作:

  • enqueue(入队):在队列尾端插入新元素。
  • dequeue(出队):移除队列前端的元素,所有剩余元素向前移动。

🌟 优点:

  • 队列始终保持整齐,前端总是从数组的第一个位置开始。

⚠️ 缺点:

  • 每次出队都需要移动剩余元素,导致时间复杂度为 (O(n)),效率低下。

📝 代码示例:

class ShiftQueue:
    def __init__(self, capacity):
        self.queue = [None] * capacity
        self.capacity = capacity
        self.size = 0
    
    def is_empty(self):
        return self.size == 0
    
    def is_full(self):
        return self.size == self.capacity
    
    def enqueue(self, item):
        if self.is_full():
            print("队列已满,无法入队")
            return
        self.queue[self.size] = item
        self.size += 1
        print(f"元素 {item} 已入队。队列状态:{self.queue}")
    
    def dequeue(self):
        if self.is_empty():
            print("队列为空,无法出队")
            return None
        item = self.queue[0]
        for i in range(1, self.size):
            self.queue[i - 1] = self.queue[i]
        self.queue[self.size - 1] = None
        self.size -= 1
        print(f"元素 {item} 已出队。队列状态:{self.queue}")
        return item

🚀 小结:

移动元素的队列实现虽然保证了队列的整齐,但由于每次出队都需要移动元素,效率非常低,不适合频繁出队的场景。


🧠 总结

通过本文的介绍,我们详细讨论了四种常见的队列实现方式:

  • 数组实现队列:简单高效,但固定大小和空间浪费是主要问题。
  • 链表实现队列:动态扩展的优势使其适用于不定长队列,但额外的指针存储增加了内存开销。
  • 循环队列:通过取模运算实现了数组空间的循环使用,适合高效空间利用的场景。
  • 移动元素队列:虽然队列始终保持整齐,但频繁移动元素带来的效率问题使其不适合大多数场景。

每种队列实现都有其优缺点,具体选择应根据实际应用场景的需求做出权衡。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/882864.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计网】从零开始掌握序列化 --- 实现网络计算器项目

​​​请各位保持头脑清醒, ​​​读些好书,做点有用的事, ​​​快快乐乐地生活。 ​​​ --- 斯蒂芬金 《肖申克的救赎》--- 从零开始掌握序列化 1 知识回顾2 服务器框架3 客户端框架4 运行测试 1 知识回顾 前面两篇文章学习中基础知识…

蓝队技能-应急响应篇Web内存马查杀JVM分析Class提取诊断反编译日志定性

知识点: 1、应急响应-Web内存马-定性&排查 2、应急响应-Web内存马-分析&日志 注:传统WEB类型的内存马只要网站重启后就清除了。 演示案例-蓝队技能-JAVA Web内存马-JVM分析&日志URL&内存查杀 0、环境搭建 参考地址:http…

常见统计量与其抽样分布

什么是统计量 我们首先给出统计量的定义:设 X 1 , X 2 , ⋯ , X n X_1,X_2,\cdots,X_n X1​,X2​,⋯,Xn​ 为来自于总体X的一个样本, g ( X 1 , X 2 , ⋯ , X n ) g(X_1,X_2,\cdots,X_n) g(X1​,X2​,⋯,Xn​) 为关于 X 1 , X 2 , ⋯ , X n X_1,X_2,\cdots,X_n X…

Python | Leetcode Python题解之第434题字符串中的单词数

题目: 题解: class Solution:def countSegments(self, s):segment_count 0for i in range(len(s)):if (i 0 or s[i - 1] ) and s[i] ! :segment_count 1return segment_count

【JS】严格模式/非严格模式的区别

JS的严格模式和非严格模式 js运行有两种模式:一种是普通模式;一种是严格模式。 严格模式是ES5添加的,是比普通模式多一部分的js规则。如果在ES5之前js解析引擎,会忽略严格模式。 js一般默认是普通模式,ES6的模块和Cla…

数据结构 ——— 数组 nums 包含了从 0 到 n 的所有整数,但是其中缺失了一个,请编写代码找出缺失的整数,并且在O(N)时间内完成

目录 题目要求 代码实现 方法1(异或法): 异或算法的时间复杂度: 方法2(等差数列公式): 等差数列公式的时间复杂度: 题目要求 整型数组 nums 包含了从 0 到 n 的所有整数&…

VPN概述

目录 定义: VPN的分类 VPN的主要应用场景 GRE VPN概念 GRE VPN的优缺点 GRE VPN应用场景和配置 GRE VPN配置流程 Router A: Router B: 定义: 虚拟专用网络(VPN)是一种通过公用网络线路建立私有网络,用于传输私…

UE学习篇ContentExample解读------Blueprint_Communication-上

文章目录 总览描述批次阅览1.1 Basic communication with a target blueprint1.2 Basic communication via actor casting1.3 Blueprint communication via actor casting to child Blueprint1.4 Communicating with all actors of a specific class 概念总结致谢: …

VulnHub-Narak靶机笔记

Narak靶机笔记 概述 Narak是一台Vulnhub的靶机,其中有简单的tftp和webdav的利用,以及motd文件的一些知识 靶机地址: https://pan.baidu.com/s/1PbPrGJQHxsvGYrAN1k1New?pwda7kv 提取码: a7kv 当然你也可以去Vulnhub官网下载 一、nmap扫…

【专题】2024年中国白酒行业数字化转型研究报告合集PDF分享(附原数据表)

原文链接:https://tecdat.cn/?p37755 消费人群趋于年轻化,消费需求迈向健康化,消费场景与渠道走向多元化,这些因素共同驱动企业凭借数据能力来适应市场的变化。从消费市场来看,消费群体、需求、场景及渠道皆展现出与…

PhpStudy | PHP 版本切换流程

关注这个软件的其他相关笔记:PhpStudy —— README-CSDN博客 在使用多样化的 PHP Web 应用程序时,选择合适的 PHP 版本至关重要。例如,一些老旧的应用程序可能是基于早期版本的 PHP 开发的,如果使用最新版本的 PHP 来运行&#xf…

【YOLO学习】YOLOv1详解

文章目录 1. 概述2. 算法流程3. 网络结构4. 损失函数 1. 概述 1. YOLO 的全称是 You Only Look Once: Unified, Real-Time Object Detection。YOLOv1 的核心思想就是利用整张图作为网络的输入,直接在输出层回归 bounding box 的位置和 bounding box 所属的类别。简单…

执行网络攻击模拟的 7 个步骤

在进攻和防守策略方面,我们可以从足球队和美式足球队身上学到很多东西。球员们会分析对方球队的策略,找出弱点,相应地调整进攻策略,最重要的是,练习、练习、再练习。作为最低要求,网络安全部门也应该这样做…

论文笔记(四十六)RobotGPT: Robot Manipulation Learning From ChatGPT

xx RobotGPT: Robot Manipulation Learning From ChatGPT 文章概括摘要I. 介绍II. 相关工作III. 方法论A. ChatGPT 提示机器人操作B. 机器人学习 IV. 实验A. 衡量标准B. 实验设置C. 模拟实验D. 真实机器人实验E. AB测试 V. 结论 文章概括 引用: article{jin2024r…

gateway--网关

在微服务架构中,Gateway(网关)是一个至关重要的组件,它扮演着多种关键角色,包括路由、负载均衡、安全控制、监控和日志记录等。 Gateway网关的作用 统一访问入口: Gateway作为微服务的统一入口&#xff0c…

Qt窗口——QMenuBar

文章目录 QMenuBar示例演示给菜单栏设置快捷键给菜单项设置快捷键添加子菜单添加分割线添加图标 QMenuBar Qt中采用QMenuBar来创建菜单栏,一个主窗口,只允许有一个菜单栏,位于主窗口的顶部、主窗口标题栏下面;一个菜单栏里面有多…

【Linux实践】实验三:LINUX系统的文件操作命令

【Linux实践】实验三:LINUX系统的文件操作命令 实验目的实验内容实验步骤及结果1. 切换和查看目录2. 显示目录下的文件3. 创建和删除目录① mkdir② rm③ rmdir 4. 输出和重定向① 输出② 重定向 > 和 >> 5. 查看文件内容① cat② head 6. 权限7. 复制8. 排…

科大讯飞智能体Python SDK接入流程

第一步:注册账号​ 进入https://passport.xfyun.cn/login,根据提示注册或登陆账号。 ​ 第二步:创建智能体 进入这个网页创建智能体,填好信息: https://xinghuo.xfyun.cn/botcenter/createbot?createtrue&qu…

【GeekBand】C++设计模式笔记4_Strategy_策略模式

1. “组件协作”模式 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。典型模式 Template MethodStrategyObserver / Event 2.…

Webpack 介绍

Webpack 介绍 Date: August 29, 2024 全文概要 Webpack概念: Webpack是一个静态的模块化的打包工具,可以为现代的 JavaSript 应用程序进行打包。 1-静态:Webpack可以将代码打包成最终的静态资源 2-模块化:webpack支持各种模块…