线性数据结构之队列

news/2024/12/14 11:50:22/

队列的基本概念

1. 特点

  • FIFO:先进先出,即第一个加入队列的元素将第一个被移除。
  • 基本操作
    • Enqueue:在队尾插入新元素。
    • Dequeue:移除队首元素并返回其值。
    • Peek:查看队首元素但不移除它。
    • isEmpty:检查队列是否为空。
    • Size:返回队列中元素的数量。

2. 应用场景

  • 资源调度:如 CPU 任务调度、操作系统的进程管理。
  • 数据缓冲:如网络数据包缓冲、I/O 缓存。
  • 广度优先搜索:在图或树中实现广度优先搜索(BFS)。

一、普通队列(Queue)

定义与实现原理

普通队列是一种典型的 FIFO 数据结构,可以用数组或链表实现。队列的起始端称为队首(Front),元素从队尾(Rear)插入并从队首移除。

1. 优点

  • 结构简单:操作仅限于队首和队尾,逻辑清晰。
  • 实现简单:基于数组或链表均可方便实现。

2. 缺点

  • 内存浪费:使用数组实现时,元素出队后,前端空间无法复用。
  • 容量固定:基于数组的实现需要预定义大小,可能导致溢出或浪费。

3. 适用场景

  • 任务调度:如打印机作业队列、操作系统进程管理。
  • 数据流缓冲:如网络传输、消息队列。

4. 示例代码(Java)

class Queue {private int[] queue;private int front;private int rear;private int capacity;private int size;public Queue(int capacity) {this.capacity = capacity;queue = new int[capacity];front = 0;rear = -1;size = 0;}// 入队操作public void enqueue(int value) {if (isFull()) {throw new IllegalStateException("队列已满,无法入队");}rear = (rear + 1) % capacity;queue[rear] = value;size++;}// 出队操作public int dequeue() {if (isEmpty()) {throw new IllegalStateException("队列为空,无法出队");}int value = queue[front];front = (front + 1) % capacity;size--;return value;}// 查看队首元素public int peek() {if (isEmpty()) {throw new IllegalStateException("队列为空,无法查看队首");}return queue[front];}public boolean isEmpty() {return size == 0;}public boolean isFull() {return size == capacity;}public int getSize() {return size;}
}

二、循环队列(Circular Queue)

定义与实现原理

循环队列在普通队列的基础上通过“环形”结构解决了内存浪费问题。即当队列尾部到达数组末端时,若数组前端有空位,则队尾可以“循环”至数组的起始位置。这种设计使得队列可以利用已出队元素的空间,提高了内存利用率。

1. 优点

  • 内存利用率高:通过循环结构实现空间复用,避免了数组前端的空位浪费。
  • 操作简单:依然只需维护队首和队尾的指针。

2. 缺点

  • 容量固定:依然需要预设大小,不支持动态扩展。

3. 适用场景

  • 缓存区:如多媒体数据流缓冲、循环缓冲区。
  • 调度系统:如 CPU 任务轮询调度。

4. 示例代码(Java)

class CircularQueue {private int[] queue;private int front;private int rear;private int capacity;private int size;public CircularQueue(int capacity) {this.capacity = capacity;queue = new int[capacity];front = 0;rear = -1;size = 0;}// 入队操作public void enqueue(int value) {if (isFull()) {throw new IllegalStateException("队列已满,无法入队");}rear = (rear + 1) % capacity;queue[rear] = value;size++;}// 出队操作public int dequeue() {if (isEmpty()) {throw new IllegalStateException("队列为空,无法出队");}int value = queue[front];front = (front + 1) % capacity;size--;return value;}public boolean isEmpty() {return size == 0;}public boolean isFull() {return size == capacity;}
}

三、双端队列(Deque)

定义与实现原理

双端队列(Deque)是一种扩展的队列,支持从两端进行插入和删除。Deque 分为 输入受限双端队列(仅允许从一端插入元素)和 输出受限双端队列(仅允许从一端删除元素)。

1. 优点

  • 灵活性高:可在队列两端操作,既支持先进先出也支持后进先出。
  • 多功能性:适合实现复杂的队列结构,如双向遍历或优先级调度。

2. 缺点

  • 实现复杂:操作两端的逻辑较复杂,且链表实现时内存消耗较大。

3. 适用场景

  • 浏览器前进后退功能:实现历史记录的快速访问。
  • 滑动窗口算法:在数据流中实时计算窗口内的最小值或最大值。

4. 示例代码(Java)

import java.util.LinkedList;class Deque {private LinkedList<Integer> deque;public Deque() {deque = new LinkedList<>();}// 队首入队public void addFront(int value) {deque.addFirst(value);}// 队尾入队public void addRear(int value) {deque.addLast(value);}// 队首出队public int removeFront() {if (deque.isEmpty()) {throw new IllegalStateException("队列为空,无法出队");}return deque.removeFirst();}// 队尾出队public int removeRear() {if (deque.isEmpty()) {throw new IllegalStateException("队列为空,无法出队");}return deque.removeLast();}// 查看队首元素public int peekFront() {if (deque.isEmpty()) {throw new IllegalStateException("队列为空");}return deque.getFirst();}// 查看队尾元素public int peekRear() {if (deque.isEmpty()) {throw new IllegalStateException("队列为空");}return deque.getLast();}
}

四、优先队列(Priority Queue)

定义与实现原理

优先队列是一种特殊的队列,元素按优先级排列。出队时优先级最高的元素先出队。可以通过 (如二叉堆)或 排序链表 实现优先队列。

1. 优点

  • 灵活性强:根据优先级决定元素出队顺序,而不是固定的 FIFO。
  • 适合处理多任务调度:优先级越高的任务越先得到处理。

2. 缺点

  • 实现复杂:需要排序或堆操作,插入和删除操作相对复杂。
  • 性能依赖于实现:不同实现方法对性能的影响较大,使用堆可达到 O(log n) 的插入和删除效率。

3. 适用场景

  • 任务调度:CPU 任务调度、网络数据包优先级管理。
  • 最短路径算法:如 Dijkstra 算法中优先处理距离最短的节点。

4. 示例代码(Java)

Java 中的 PriorityQueue 类实现了优先队列,以下示例展示了使用 Java 内置优先队列。

import java.util.PriorityQueue;public class PriorityQueueExample {public static void main(String[] args) {// 创建优先队列,默认情况下,优先级越小的元素越先出队PriorityQueue<Integer> pq = new PriorityQueue<>();pq.add(30);pq.add(10);pq.add(20);// 出队,按优先级顺序出队while (!pq.isEmpty()) {System.out.println(pq.poll()); // 输出 10 20 30}}
}

总结对比

类型特点优点缺点适用场景
普通队列先进先出(FIFO)结构简单,操作高效内存浪费(数组实现)任务调度、数据流缓冲
循环队列环形结构,解决内存浪费问题内存利用率高容量固定缓冲区、轮询调度
双端队列支持两端插入和删除灵活性高实现复杂浏览器历史、滑动窗口
优先队列按优先级出队灵活性强,适合调度任务实现复杂,性能依赖于实现方法任务调度、最短路径算法

根据具体需求和场景选择合适的队列类型,能更好地解决问题。


http://www.ppmy.cn/news/1544432.html

相关文章

基于SSM+小程序的购物管理系统1

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM小程序的购物管理系统1&#xff0c;可以实现首页、个人中心、商品分类管理、商品信息管理、特价商品管理、用户管理、留言板管理、系统管理、订单管理等功能。方便用户对首页、商品…

数据结构与算法 - 基础

本文首发于 个人博客 程序 数据结构 算法 其实很多同学知道数据结构与算法很重要&#xff0c;但是却不明觉厉。 这里我们看一个简单的题&#xff1a; 对自然数从1到100的求和 最简单的设计无非是&#xff1a; void addNum () { int total 0; for (int i 1; i < 1…

两个时间戳计算时间差

提示&#xff1a;文章 文章目录 前言一、背景二、2.12.2 三、3.1 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 最近 二、 2.1 void GetTimeWithDis::GetTimeWithDisInterval() {for (int i 1; i < m_timeWithDis.size(); i) {std::string str1 m_…

vue系列==Vuex状态管理器

1、Vuex状态管理器 1、创建一个Vuex的store对象来统一管理多个组件之间共享的状态数据。在创建store对象时&#xff0c;可以配置state、getters、mutations和actions这4个对象&#xff0c;组件之间共享的状态数据在state对象中指定&#xff0c;而基于状态数据的计算属性可以在g…

NVR监测软件/设备EasyNVR多品牌NVR管理工具/设备对城市安全有哪些具体益处?

在智慧城市的建设中&#xff0c;各种先进的技术系统正发挥着越来越重要的作用。其中&#xff0c;NVR监测软件/设备EasyNVR作为一种高效的视频边缘计算网关&#xff0c;不仅能够实现视频数据的采集、编码和存储&#xff0c;还能与其他智慧城市系统进行深度集成&#xff0c;共同推…

什么是CSS 选择器?都有哪些?

写在前面 CSS 选择器是 CSS 样式表中最重要的部分之一。它们允许你精确地选择 HTML 文档中的元素&#xff0c;并应用样式。理解和掌握 CSS 选择器是成为一名优秀的前端开发者的关键。 基本选择器 元素选择器&#xff1a;选择特定的 HTML 元素。例如&#xff0c;p 选择器将选择…

OceanBase V4.3.3,首个面向实时分析场景的GA版本发布

在10月23日举办的 OceanBase年度发布会 上&#xff0c;我们怀着激动之情&#xff0c;正式向大家宣布了 OceanBase 4.3.3 GA 版的正式发布&#xff0c;这也是OceanBase 为实时分析&#xff08;AP&#xff09;场景打造的首个GA版本。 2024 年初&#xff0c;我们推出了 4.3.0 版本…

从0到1构建一个RAG检索增强系统

RAG&#xff08;Retrieve Augment Generation&#xff0c;检索增强&#xff09;是“驯服”大语言模型的主要手段之一。它允许大语言模型在从固定的数据库中抽取相关内容的基础上生成答案&#xff0c;从而限制随意发挥&#xff0c;提升答案的可靠性。 核心组件&#xff1a; RA…