数据结构 学习 队列 2025年6月14日 11点22分

循环队列

循环队列是一种线性数据结构,它遵循FIFO(先进先出)原则,但与普通队列不同的是,循环队列的最后一个元素连接回第一个元素,形成一个环形结构。这种设计有效解决了普通队列的"假溢出"问题,可以更高效地利用存储空间。

基本概念

1. 循环队列特点

  • 环形结构:队尾连接队首,形成循环

  • 高效空间利用:重用出队元素释放的空间

  • 两个指针:front(队首)和rear(队尾)

  • 判空判满:需要特殊处理区分队列空和满的状态

2. 基本操作

  • Enqueue:向队尾添加元素

  • Dequeue:从队首移除元素

  • Front:获取队首元素

  • Rear:获取队尾元素

  • isEmpty:判断队列是否为空

  • isFull:判断队列是否已满

实际应用
  1. CPU任务调度:循环分配CPU时间片

  2. 内存管理:循环缓冲区处理数据流

  3. 网络数据包处理:按顺序处理到达的数据包

  4. 打印机队列:管理多个打印任务

  5. 音乐播放列表:循环播放歌曲

//数组实现(固定大小)
class CircularQueue {
private:vector<int> data;int front;int rear;int size;public:CircularQueue(int k) {data.resize(k);front = -1;rear = -1;size = k;}bool enQueue(int value) {if (isFull()) return false;if (isEmpty()) front = 0;rear = (rear + 1) % size;data[rear] = value;return true;}bool deQueue() {if (isEmpty()) return false;if (front == rear) {front = -1;rear = -1;} else {front = (front + 1) % size;}return true;}int Front() {if (isEmpty()) return -1;return data[front];}int Rear() {if (isEmpty()) return -1;return data[rear];}bool isEmpty() {return front == -1;}bool isFull() {return (rear + 1) % size == front;}
};
//链表实现
class Node {
public:int val;Node* next;Node(int value) : val(value), next(nullptr) {}
};class LinkedCircularQueue {
private:Node *front, *rear;public:LinkedCircularQueue() : front(nullptr), rear(nullptr) {}bool enQueue(int value) {Node* newNode = new Node(value);if (rear == nullptr) {front = rear = newNode;} else {rear->next = newNode;rear = newNode;}rear->next = front; // 形成循环return true;}bool deQueue() {if (isEmpty()) return false;int value = front->val;Node* temp = front;if (front == rear) {front = rear = nullptr;} else {front = front->next;rear->next = front; // 保持循环}delete temp;return true;}int Front() {if (isEmpty()) return -1;return front->val;}int Rear() {if (isEmpty()) return -1;return rear->val;}bool isEmpty() {return front == nullptr;}// 链表实现通常不考虑满的情况(除非内存耗尽)bool isFull() {return false; }
};
示例
#include <iostream>
#include <vector>using namespace std;class CircularQueue {
private:vector<int> data;  // 使用vector存储队列元素int front;         // 队首指针int rear;          // 队尾指针int size;          // 队列容量public:// 构造函数,初始化队列容量CircularQueue(int k) {data.resize(k); // 分配存储空间front = -1;     // 初始时队首指针为-1表示空队列rear = -1;      // 初始时队尾指针为-1表示空队列size = k;       // 设置队列容量}// 入队操作bool enQueue(int value) {if (isFull()) {  // 检查队列是否已满cout << "队列已满,无法插入 " << value << endl;return false;}if (isEmpty()) { // 如果是第一个元素front = 0;   // 初始化队首指针}rear = (rear + 1) % size; // 循环移动队尾指针data[rear] = value;       // 存储元素cout << "插入 " << value << " 成功" << endl;return true;}// 出队操作bool deQueue() {if (isEmpty()) {  // 检查队列是否为空cout << "队列为空,无法删除" << endl;return false;}int value = data[front]; // 获取队首元素if (front == rear) {     // 如果队列中只有一个元素front = -1;          // 重置队首指针rear = -1;           // 重置队尾指针} else {front = (front + 1) % size; // 循环移动队首指针}cout << "删除 " << value << " 成功" << endl;return true;}// 获取队首元素int Front() {if (isEmpty()) return -1; // 队列为空返回-1return data[front];       // 返回队首元素}// 获取队尾元素int Rear() {if (isEmpty()) return -1; // 队列为空返回-1return data[rear];        // 返回队尾元素}// 判断队列是否为空bool isEmpty() {return front == -1; // 队首指针为-1表示空队列}// 判断队列是否已满bool isFull() {return (rear + 1) % size == front; // 队尾下一个位置是队首表示队列已满}// 显示队列内容void display() {if (isEmpty()) {  // 检查队列是否为空cout << "队列为空" << endl;return;}cout << "队列元素: ";if (rear >= front) {  // 队列元素没有跨越数组边界for (int i = front; i <= rear; i++)cout << data[i] << " ";} else {  // 队列元素跨越数组边界(循环情况)for (int i = front; i < size; i++)  // 打印队首到数组末尾的元素cout << data[i] << " ";for (int i = 0; i <= rear; i++)    // 打印数组开头到队尾的元素cout << data[i] << " ";}cout << endl;}
};int main() {// 创建容量为5的循环队列CircularQueue q(5);// 入队操作测试q.enQueue(1);q.enQueue(2);q.enQueue(3);q.enQueue(4);q.enQueue(5);q.enQueue(6); // 队列已满,无法插入// 显示队列内容q.display();// 出队操作测试q.deQueue();q.deQueue();// 显示队列内容q.display();// 继续入队测试循环特性q.enQueue(6);q.enQueue(7);// 显示队列内容q.display();// 获取队首和队尾元素cout << "队首元素: " << q.Front() << endl;cout << "队尾元素: " << q.Rear() << endl;return 0;
}

双向队列

双向队列是一种非常实用的数据结构,它提供了比普通队列和栈更灵活的操作方式,在算法设计和系统开发中都有广泛应用。

一种允许在两端进行插入和删除操作的线性数据结构。它结合了栈和队列的特性,提供了更灵活的数据操作方式。

基本概念
1. 双向队列特点
  • 双端操作:可以在队首和队尾进行插入和删除

  • 灵活性强:既可以作为队列使用(FIFO),也可以作为栈使用(LIFO)

  • 多种实现方式:可以使用数组或链表实现

2. 基本操作
  • push_front:在队首插入元素

  • push_back:在队尾插入元素

  • pop_front:删除队首元素

  • pop_back:删除队尾元素

  • front:获取队首元素

  • back:获取队尾元素

  • size:获取元素数量

  • empty:判断是否为空

//基与双链表实现#include <iostream>
using namespace std;// 双向链表节点
struct Node {int data;Node* prev;Node* next;Node(int val) : data(val), prev(nullptr), next(nullptr) {}
};class Deque {
private:Node* front;Node* rear;int count;public:Deque() : front(nullptr), rear(nullptr), count(0) {}~Deque() {while (!empty()) {pop_front();}}// 在队首插入void push_front(int val) {Node* newNode = new Node(val);if (empty()) {front = rear = newNode;} else {newNode->next = front;front->prev = newNode;front = newNode;}count++;}// 在队尾插入void push_back(int val) {Node* newNode = new Node(val);if (empty()) {front = rear = newNode;} else {newNode->prev = rear;rear->next = newNode;rear = newNode;}count++;}// 删除队首元素void pop_front() {if (empty()) {cout << "Deque is empty!" << endl;return;}Node* temp = front;front = front->next;if (front == nullptr) {rear = nullptr;} else {front->prev = nullptr;}delete temp;count--;}// 删除队尾元素void pop_back() {if (empty()) {cout << "Deque is empty!" << endl;return;}Node* temp = rear;rear = rear->prev;if (rear == nullptr) {front = nullptr;} else {rear->next = nullptr;}delete temp;count--;}// 获取队首元素int get_front() {if (empty()) {cout << "Deque is empty!" << endl;return -1;}return front->data;}// 获取队尾元素int get_back() {if (empty()) {cout << "Deque is empty!" << endl;return -1;}return rear->data;}// 获取元素数量int size() {return count;}// 判断是否为空bool empty() {return count == 0;}// 打印队列内容void display() {Node* current = front;cout << "Deque: [";while (current != nullptr) {cout << current->data;if (current->next != nullptr) {cout << ", ";}current = current->next;}cout << "]" << endl;}
};
//基于循环数组的实现
#include <iostream>
#include <vector>
using namespace std;class ArrayDeque {
private:vector<int> data;int front;int rear;int capacity;int count;public:ArrayDeque(int k) : capacity(k), front(0), rear(0), count(0) {data.resize(k);}// 在队首插入bool push_front(int val) {if (isFull()) {cout << "Deque is full!" << endl;return false;}front = (front - 1 + capacity) % capacity;data[front] = val;count++;return true;}// 在队尾插入bool push_back(int val) {if (isFull()) {cout << "Deque is full!" << endl;return false;}data[rear] = val;rear = (rear + 1) % capacity;count++;return true;}// 删除队首元素bool pop_front() {if (isEmpty()) {cout << "Deque is empty!" << endl;return false;}front = (front + 1) % capacity;count--;return true;}// 删除队尾元素bool pop_back() {if (isEmpty()) {cout << "Deque is empty!" << endl;return false;}rear = (rear - 1 + capacity) % capacity;count--;return true;}// 获取队首元素int get_front() {if (isEmpty()) {cout << "Deque is empty!" << endl;return -1;}return data[front];}// 获取队尾元素int get_back() {if (isEmpty()) {cout << "Deque is empty!" << endl;return -1;}return data[(rear - 1 + capacity) % capacity];}// 判断是否为空bool isEmpty() {return count == 0;}// 判断是否已满bool isFull() {return count == capacity;}// 获取元素数量int size() {return count;}// 打印队列内容void display() {cout << "Deque: [";for (int i = 0; i < count; i++) {cout << data[(front + i) % capacity];if (i < count - 1) {cout << ", ";}}cout << "]" << endl;}
};

实际应用
  1. 撤销操作:许多编辑器使用双向队列实现撤销功能

  2. 滑动窗口:解决滑动窗口最大值等问题

  3. 任务调度:操作系统中的任务调度算法

  4. 浏览器历史记录:前进和后退功能

  5. 回文检查:可以从两端同时检查字符

 示例代码
int main() {// 测试链表实现的Dequecout << "Linked List Deque:" << endl;Deque dq;dq.push_back(10);dq.push_back(20);dq.push_front(5);dq.display(); // [5, 10, 20]cout << "Front: " << dq.get_front() << endl; // 5cout << "Back: " << dq.get_back() << endl;   // 20dq.pop_front();dq.display(); // [10, 20]dq.pop_back();dq.display(); // [10]// 测试数组实现的Dequecout << "\nArray Deque:" << endl;ArrayDeque adq(5);adq.push_back(100);adq.push_front(50);adq.push_back(200);adq.display(); // [50, 100, 200]cout << "Front: " << adq.get_front() << endl; // 50cout << "Back: " << adq.get_back() << endl;   // 200adq.pop_front();adq.display(); // [100, 200]adq.pop_back();adq.display(); // [100]return 0;
}

单调队列

单调队列是一种特殊的队列数据结构,它保持队列中元素的单调性(单调递增或单调递减)。这种数据结构常用于解决滑动窗口相关问题,能够高效地获取窗口中的最大值或最小值。

单调队列通过维护数据的单调性,将原本O(nk)的滑动窗口问题优化到O(n),是解决一类极值问题的有效工具。掌握其核心思想和实现技巧对算法能力提升有很大帮助

基本概念
1. 单调队列特性
  • 单调性:队列中元素保持单调递增或单调递减

  • 双端操作:可以从队首和队尾进行插入和删除

  • 高效性:能在O(1)时间内获取当前窗口的最大值/最小值

2. 常见应用场景
  • 滑动窗口最大值/最小值

  • 股票价格分析

  • 数据流中的极值问题

  • 动态规划优化

//单调递减队列 用于求滑动窗口最大值)#include <deque>
#include <vector>using namespace std;class MonotonicQueue {
private:deque<int> data; // 存储元素的下标public:// 在队尾添加元素,维护单调递减性void push(int idx, const vector<int>& nums) {while (!data.empty() && nums[data.back()] <= nums[idx]) {data.pop_back(); // 移除比当前元素小的元素}data.push_back(idx);}// 获取当前队列最大值(队首元素)int max() {return data.front();}// 移除超出窗口范围的元素void pop(int idx) {while (!data.empty() && data.front() <= idx) {data.pop_front();}}// 判断队列是否为空bool empty() {return data.empty();}
};vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> result;MonotonicQueue mq;// 初始化第一个窗口for (int i = 0; i < k; ++i) {mq.push(i, nums);}result.push_back(nums[mq.max()]);// 滑动窗口for (int i = k; i < nums.size(); ++i) {mq.pop(i - k); // 移除离开窗口的元素mq.push(i, nums); // 添加新元素result.push_back(nums[mq.max()]);}return result;
}
//单调递增队列 用于求滑动窗口最小值)
class MonotonicQueueMin {
private:deque<int> data; // 存储元素的下标public:void push(int idx, const vector<int>& nums) {while (!data.empty() && nums[data.back()] >= nums[idx]) {data.pop_back(); // 移除比当前元素大的元素}data.push_back(idx);}int min() {return data.front();}void pop(int idx) {while (!data.empty() && data.front() <= idx) {data.pop_front();}}bool empty() {return data.empty();}
};vector<int> minSlidingWindow(vector<int>& nums, int k) {vector<int> result;MonotonicQueueMin mq;for (int i = 0; i < k; ++i) {mq.push(i, nums);}result.push_back(nums[mq.min()]);for (int i = k; i < nums.size(); ++i) {mq.pop(i - k);mq.push(i, nums);result.push_back(nums[mq.min()]);}return result;
}
经典应用
//滑动窗口最大值
vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> res;deque<int> dq; // 存储下标for (int i = 0; i < nums.size(); ++i) {// 移除超出窗口范围的元素while (!dq.empty() && dq.front() <= i - k) {dq.pop_front();}// 维护单调递减性while (!dq.empty() && nums[dq.back()] <= nums[i]) {dq.pop_back();}dq.push_back(i);// 窗口形成后开始记录结果if (i >= k - 1) {res.push_back(nums[dq.front()]);}}return res;
}
//队列的最大值class MaxQueue {
private:queue<int> data;deque<int> max_q;public:MaxQueue() {}int max_value() {if (max_q.empty()) return -1;return max_q.front();}void push_back(int value) {data.push(value);while (!max_q.empty() && max_q.back() < value) {max_q.pop_back();}max_q.push_back(value);}int pop_front() {if (data.empty()) return -1;int val = data.front();data.pop();if (val == max_q.front()) {max_q.pop_front();}return val;}
};
//股票的价格跨度
class StockSpanner {
private:stack<pair<int, int>> st; // {price, span}public:StockSpanner() {}int next(int price) {int span = 1;while (!st.empty() && st.top().first <= price) {span += st.top().second;st.pop();}st.push({price, span});return span;}
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打造丝滑滚动体验:Scroll-driven Animations 正式上线!

&#x1f300; 打造丝滑滚动体验&#xff1a;Scroll-driven Animations 正式上线&#xff01; &#x1f6a8; 告别 JS 手动监听滚动条&#xff0c;CSS 新能力让你用两行代码实现高级滚动动效。 &#x1f50d; 什么是 Scroll-driven Animations&#xff1f; Scroll-driven anim…

知识体系_研究模型_价格敏感度测试模型(PSM)

1 概述 价格敏感度测试模型(Price Sensitivity Measurement,PSM) ,通过调研潜在用户对于不同价格的满意或接受程度,从而制定出合适的产品价格。 价格敏感度PSM模型的分析一般分为以下几个步骤: (1)确定多个价格 (2)通过一定的方式(通常是问卷)收集目标客户对不同价…

C++11函数封装器 std::function

✅ 1. 什么是 std::function std::function 是 C11 引入的标准库工具&#xff0c;是一个通用的函数封装器&#xff0c;可以包装以下任意可调用对象&#xff1a; 普通函数Lambda 表达式函数指针成员函数指针函数对象&#xff08;也叫仿函数&#xff0c;定义了 operator() 的类…

centos系统docker配置`milvus-standalone`教程

本人使用的是京东云服务器docker配置milvus 参考教程&#xff1a;https://blog.csdn.net/withme977/article/details/137270087 需要注意&#xff1a;虚拟机安装pymilvus和docker安装milvus版本需要对应&#xff0c;否则会出现connection失败问题 查看虚拟机pymilvus版本&…

AI for 数据分析:技术演进与应用实践

一、AI 数据分析的核心定义与技术演进 概念延伸&#xff1a;从传统分析到智能分析 传统数据分析工作&#xff0c;主要依赖人工使用 Excel、SPSS 等统计工具进行建模与分析。这种方式不仅效率较低&#xff0c;而且对专业人员的依赖度极高。而 AI 驱动的数据分析则借助机器学习…

stm32 f103c8t6仿真 串口收发测试

C8T6串口概述 STM32F103C8T6微控制器包含3个串口模块&#xff1a; USART1 (高级串口) USART2 USART3 (部分型号可能标记为UART3) 引脚分布图 USART1 (串口1) 基本特性 类型&#xff1a;全功能USART(通用同步异步收发器) 通信模式&#xff1a; 全双工异步通信 单线半…

语言特性适用的场景:卫星、火箭控制系统用什么开发语言?

核心飞行控制系统开发语言 卫星、火箭及相关航天系统的软件开发对可靠性、实时性、安全性有极高要求&#xff0c;因此语言选择需严格匹配这些需求。以下是航天领域常用的编程语言及其应用场景分析&#xff1a; 一、核心飞行控制与嵌入式系统&#xff1a;C、C、Ada 航天器的核…

AI for Science:智能科技如何重塑科学研究

AI与科学研究的邂逅 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;作为一门致力于模拟人类智能的交叉学科&#xff0c;近年来已经从实验室走向现实世界的各个角落&#xff0c;而科学研究领域正是其最具变革潜力的舞台之一。AI的核心在于通过算法…

项目三 - 任务7:开发名片管理系统

在本次项目三的任务7中&#xff0c;我们成功开发了一个功能全面的名片管理系统。该系统采用Java语言&#xff0c;基于MVC&#xff08;模型-视图-控制器&#xff09;架构模式&#xff0c;实现了用户登录、名片的增删改查等核心功能。通过设计Card类来封装名片信息&#xff0c;Ca…

MySQL 8.0 OCP 英文题库解析(十八)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题161~170 试题1…

leetcode_503 下一个更大元素

1. 题意 在一个循环数组中&#xff0c;找到下一个比它大的数。 2. 题解 也不知道怎么就单调栈了&#xff0c;可能是刷出来的吧。。。 还是来解释一下吧&#xff01;&#xff01;&#xff01; 如果有新元素入栈 c c c&#xff0c; 那么在栈内的元素只要小于新元素的 s s s…

在postgresql中,group by时取第一个值

在postgresql中,group by时,uuid类型的字段可以用哪个聚集函数: SELECT create_user , (array_agg(myid))[1] AS first_uuid FROM "t_resource_data" GROUP BY create_user 人大金仓、PostgreSQL使用GROUP BY聚合后&#xff0c;取第一个值或最后一个值的办_pgsql gro…

【FineDance】ModuleNotFoundError: No module named ‘pytorch3d‘

pytorch3d Traceback (most recent call last): File “/home/zhangbin/perfwork/01_ai/13_FineDance/data/code/pre_motion.py”, line 12, in from dataset.quaternion import ax_to_6v, ax_from_6v File “/home/zhangbin/perfwork/01_ai/13_FineDance/dataset/quaternion.…

MySQL 调优笔记

1.如何定位慢查询? 定位慢查询主要依靠 MySQL 的慢查询日志配合工具如 pt-query-digest &#xff0c;mysqldumpslow 进行分析&#xff0c;或者通过 performance_schema 进行实时监控&#xff0c;进一步可以使用 EXPLAIN 分析执行计划。 -> 开启慢查询日志 -- 查看慢查询…

嵌入式 STM32 开发问题:烧录 STM32CubeMX 创建的 Keil 程序没有反应

烧录 STM32CubeMX 创建的 Keil 程序没有反应问题原因 大概率是因为没有勾选 Reset and Run&#xff0c;程序成功烧录到&#xff0c;但芯片不会自动复位并执行&#xff0c;而是保持停止状态 处理策略 在 Keil 中勾选 Reset and Run 点击 【Options for Target】 点击 【Debu…

Flower框架中noise_multiplier与clipped_count_stddev的关系

noise_multiplier 与 clipped_count_stddev 的数学关系 在差分隐私联邦学习中&#xff0c;noise_multiplier 和 clipped_count_stddev 是两个核心参数&#xff0c;它们共同决定了隐私保护强度和模型精度的权衡。理解它们的关系需要从差分隐私的数学原理入手&#xff1a; 1. 高…

Laravel 从版本 5 到 12 每个版本都引入了一些新的特性、改进和弃用的功能

Laravel 从版本 5 到 12 经历了多次更新,每个版本都引入了一些新的特性、改进和弃用的功能。下面是这些主要版本之间的关键区别: Laravel 5 Lumen: 引入了微框架 Lumen。Elixir: Elixir 是一个用于编译和合并前端资源的工具,后来被 Laravel Mix 取代。Middleware Groups: 引…

Lambda 表达式的语法与使用:更简洁、更灵活的函数式编程!

全文目录&#xff1a; 开篇语Lambda 表达式的语法与使用&#xff1a;更简洁、更灵活的函数式编程一、Lambda 表达式的语法1.1 Lambda 表达式的基本语法形式 二、Lambda 表达式的使用2.1 Lambda 表达式与匿名内部类的对比代码示例&#xff1a;使用匿名内部类和 Lambda 表达式实现…

从0到1开发一个自己的工具 MCP 并发布到 test PyPi(Python个人版)

目录 1. 我理解的 MCP2. 写一个自己的MCP然后发布到 PyPi 上&#xff0c;包括加法工具和获取当前 ip 工具2.1 先碎碎念一下 uv2.2 初始化项目&#xff08;全程在 cmd 下运行命令&#xff09;2.3 添加 mcp 依赖2.4 添加 server.py&#xff0c;先把加法功能添加上2.5 运行并测试加…