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

devtools/2024/9/25 8:47:49/

🎓 【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] * capacityself.capacity = capacityself.front = 0self.rear = -1self.size = 0def is_empty(self):return self.size == 0def is_full(self):return self.size == self.capacitydef enqueue(self, item):if self.is_full():print("队列已满,无法入队")returnself.rear += 1self.queue[self.rear] = itemself.size += 1print(f"元素 {item} 已入队。队列状态:{self.queue}")def dequeue(self):if self.is_empty():print("队列为空,无法出队")return Noneitem = self.queue[self.front]self.queue[self.front] = Noneself.front += 1self.size -= 1print(f"元素 {item} 已出队。队列状态:{self.queue}")return item

🚀 小结:

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


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

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

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

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

🛠 主要操作:

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

🌟 优点:

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

⚠️ 缺点:

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

📝 代码示例:

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

🚀 小结:

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


🔄 循环队列(Circular Queue) 🔄

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

🎨 形象类比:环形传送带

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

🛠 主要操作:

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

🌟 优点:

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

⚠️ 缺点:

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

📝 代码示例:

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

🚀 小结:

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


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

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

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

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

🛠 主要操作:

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

🌟 优点:

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

⚠️ 缺点:

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

📝 代码示例:

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

🚀 小结:

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


🧠 总结

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

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

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


http://www.ppmy.cn/devtools/116877.html

相关文章

高等数学大纲

一、函数与极限 函数的概念 函数的定义函数的性质(单调性、奇偶性、周期性)初等函数(代数函数、三角函数、指数函数、对数函数) 极限 极限的定义极限的性质无穷小与无穷大夹挤定理左右极限与极限的存在性 二、连续性 连续函数的定…

【计算机网络 - 基础问题】每日 3 题(二十)

✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/fYaBd 📚专栏简介:在这个专栏中,我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏&…

MyBatis—Plus 快速上手【后端 22】

MyBatis-Plus 使用入门指南 前言 在Java的持久层框架中,MyBatis因其灵活性和易用性而广受欢迎。然而,随着项目规模的扩大,MyBatis的一些重复性工作(如CRUD操作)开始显得繁琐。为了解决这一问题,MyBatis-Pl…

Linux 系统安装python

在Linux系统上安装Python的步骤相对直接,但具体步骤可能会因Linux发行版的不同而有所差异。以下是一个通用的安装流程,适用于大多数Linux系统: 1. 检查是否已安装Python 首先,打开终端并输入以下命令来检查系统是否已经安装了Py…

组合式 API 和选项式 API的区别

一、区别 设计思想:options API 偏向于填充式,规定了方法应该写在那里,比如 methods,computed,watch 等,而 compositionAPI 更灵活 使用方式:compositionAPI 全部写在 setup(&…

JSP(Java Server Pages)基础使用二

简单练习在jsp页面上输出出乘法口诀表 既然大家都是来看这种代码的人了&#xff0c;那么这种输出乘法口诀表的这种简单算法肯定是难不住大家了&#xff0c;所以这次主要是来说jsp的使用格式问题。 <%--Created by IntelliJ IDEA.User: ***Date: 2024/7/18Time: 11:26To ch…

react hooks--useCallback

概述 useCallback缓存的是一个函数&#xff0c;主要用于性能优化!!! 基本用法 如何进行性能的优化呢&#xff1f; useCallback会返回一个函数的 memoized&#xff08;记忆的&#xff09; 值&#xff1b;在依赖不变的情况下&#xff0c;多次定义的时候&#xff0c;返回的值是…

DC-DC动态响应度的优化

DC-DC动态响应度的优化 以MP2315模块为例到底怎么样才能改变动态响应度呢&#xff1f;修改前馈电容修改电感也可以改善动态响应度 以MP2315模块为例 DC-DC输出位置再增加电容 从下面的波形图看出&#xff0c;多了一颗输出电容之后的结果&#xff0c;似乎有那么一点点作用但是…