《数据结构》--队列【各种实现,算法推荐】
一、认识队列
队列是一种常见的数据结构,按照先进先出(FIFO,First In First Out)的原则排列数据。也就是说,最早进入队列的元素最先被移除。队列主要支持两种基本操作:
入队(enqueue):将元素添加到队列的尾部。
出队(dequeue):从队列的头部移除并返回元素。
队列的其他操作:
创建队列:初始化一个空队列。
查看队列头部元素:返回但不移除队列的头部元素(通常称为“peek”或“front”)。
判断队列是否为空:检查队列中是否还有元素。
获取队列大小:返回队列中元素的数量。
1.顺序队列
顺序队列即用顺序结构存储,数组实现:
#include <iostream> class Queue {
private: int* arr; int front; int rear; int capacity;
public: Queue(int size) { arr = new int[size]; capacity = size; front = 0; rear = -1; } ~Queue() { delete[] arr; } void enqueue(int item) { if (rear == capacity - 1) { std::cout << "Queue is full!" << std::endl; return; } arr[++rear] = item; } int dequeue() { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } return arr[front++]; } int peek() { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } return arr[front]; } bool is_empty() const { return front > rear; } int size() const { return rear - front + 1; }
}; int main() { Queue q(5); q.enqueue(10); q.enqueue(20); q.enqueue(30); std::cout << "Front element: " << q.peek() << std::endl; // 输出 10 std::cout << "Dequeued element: " << q.dequeue() << std::endl; // 输出 10 std::cout << "Queue size: " << q.size() << std::endl; // 输出 2 return 0;
}
2.链式队列
链式队列即用链式存储,用链表实现:
#include <iostream> class Node {
public: int data; Node* next; Node(int value) : data(value), next(nullptr) {}
}; class Queue {
private: Node* front; Node* rear; int size;
public: Queue() : front(nullptr), rear(nullptr), size(0) {} ~Queue() { while (!is_empty()) { dequeue(); } } void enqueue(int item) { Node* newNode = new Node(item); if (rear) { rear->next = newNode; } rear = newNode; if (!front) { front = rear; } size++; } int dequeue() { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } Node* temp = front; int value = front->data; front = front->next; delete temp; if (!front) { rear = nullptr; // 队列变空 } size--; return value; } int peek() { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } return front->data; } bool is_empty() const { return size == 0; } int get_size() const { return size; }
}; int main() { Queue q; q.enqueue(10); q.enqueue(20); q.enqueue(30); std::cout << "Front element: " << q.peek() << std::endl; // 输出 10 std::cout << "Dequeued element: " << q.dequeue() << std::endl; // 输出 10 std::cout << "Queue size: " << q.get_size() << std::endl; // 输出 2 return 0;
}
二、双端队列
1.顺序双端队列
#include <iostream> class Deque {
private: int* arr; int front; int rear; int capacity;
public: Deque(int size) { arr = new int[size]; capacity = size; front = -1; rear = 0; } ~Deque() { delete[] arr; } void insertFront(int item) { if (is_full()) { std::cout << "Deque is full!" << std::endl; return; } if (is_empty()) { front = 0; rear = 0; } else { front = (front - 1 + capacity) % capacity; // 循环移动前指针 } arr[front] = item; } void insertRear(int item) { if (is_full()) { std::cout << "Deque is full!" << std::endl; return; } if (is_empty()) { front = 0; rear = 0; } else { rear = (rear + 1) % capacity; // 循环移动后指针 } arr[rear] = item; } int deleteFront() { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } int item = arr[front]; if (front == rear) { // 仅有一个元素 front = -1; rear = 0; } else { front = (front + 1) % capacity; // 循环移动前指针 } return item; } int deleteRear() { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } int item = arr[rear]; if (front == rear) { // 仅有一个元素 front = -1; rear = 0; } else { rear = (rear - 1 + capacity) % capacity; // 循环移动后指针 } return item; } int getFront() const { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } return arr[front]; } int getRear() const { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } return arr[rear]; } bool is_empty() const { return front == -1; } bool is_full() const { return (rear + 1) % capacity == front; }
}; int main() { Deque dq(5); dq.insertRear(10); dq.insertRear(20); dq.insertFront(5); dq.insertFront(0); std::cout << "Front element: " << dq.getFront() << std::endl; // 输出 0 std::cout << "Rear element: " << dq.getRear() << std::endl; // 输出 20 dq.deleteFront(); // 删除 0 dq.deleteRear(); // 删除 20 std::cout << "Front element after deletions: " << dq.getFront() << std::endl; // 输出 5 return 0;
}
2.链式双端队列
双端队列的链式存储,采用双向链表来实现模拟:
#include <iostream> class Node {
public: int data; Node* next; Node* prev; Node(int value) : data(value), next(nullptr), prev(nullptr) {}
}; class Deque {
private: Node* front; Node* rear;
public: Deque() : front(nullptr), rear(nullptr) {} ~Deque() { while (!is_empty()) { deleteFront(); } } void insertFront(int item) { Node* newNode = new Node(item); if (is_empty()) { front = rear = newNode; } else { newNode->next = front; front->prev = newNode; front = newNode; } } void insertRear(int item) { Node* newNode = new Node(item); if (is_empty()) { front = rear = newNode; } else { rear->next = newNode; newNode->prev = rear; rear = newNode; } } int deleteFront() { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } Node* temp = front; int value = front->data; front = front->next; if (front) { front->prev = nullptr; } else { rear = nullptr; // 如果队列变空 } delete temp; return value; } int deleteRear() { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } Node* temp = rear; int value = rear->data; rear = rear->prev; if (rear) { rear->next = nullptr; } else { front = nullptr; // 如果队列变空 } delete temp; return value; } int getFront() const { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } return front->data; } int getRear() const { if (is_empty()) { std::cout << "Deque is empty!" << std::endl; return -1; // 或抛出异常 } return rear->data; } bool is_empty() const { return front == nullptr; }
}; int main() { Deque dq; dq.insertRear(10); dq.insertRear(20); dq.insertFront(5); dq.insertFront(0); std::cout << "Front element: " << dq.getFront() << std::endl; // 输出 0 std::cout << "Rear element: " << dq.getRear() << std::endl; // 输出 20 dq.deleteFront(); // 删除 0 dq.deleteRear(); // 删除 20 std::cout << "Front element after deletions: " << dq.getFront() << std::endl; // 输出 5 return 0;
}
三、循环队列
1.顺序循环队列
#include <iostream> class CircularQueue {
private: int* arr; // 存储队列元素的数组 int front; // 队列头指针 int rear; // 队列尾指针 int capacity; // 队列的最大容量 int count; // 当前队列中的元素数量 public: CircularQueue(int size) { arr = new int[size]; capacity = size; front = 0; rear = -1; count = 0; } ~CircularQueue() { delete[] arr; } // 入队操作 void enqueue(int item) { if (is_full()) { std::cout << "Queue is full!" << std::endl; return; } rear = (rear + 1) % capacity; // 循环移动尾指针 arr[rear] = item; count++; } // 出队操作 int dequeue() { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } int item = arr[front]; front = (front + 1) % capacity; // 循环移动头指针 count--; return item; } // 获取队头元素 int peek() const { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } return arr[front]; } // 检查队列是否为空 bool is_empty() const { return count == 0; } // 检查队列是否已满 bool is_full() const { return count == capacity; } // 获取当前队列大小 int size() const { return count; }
}; int main() { CircularQueue cq(5); // 创建一个容量为5的循环队列 cq.enqueue(10); cq.enqueue(20); cq.enqueue(30); cq.enqueue(40); cq.enqueue(50); std::cout << "Front element: " << cq.peek() << std::endl; // 输出 10 std::cout << "Dequeued: " << cq.dequeue() << std::endl; // 输出 10 std::cout << "Front element after dequeue: " << cq.peek() << std::endl; // 输出 20 cq.enqueue(60); // 尝试入队一个新元素 std::cout << "Front element after enqueue: " << cq.peek() << std::endl; // 输出 20 return 0;
}
2.链式循环队列
采用循环链表的方式来实现循环队列
#include <iostream> class Node {
public: int data; Node* next; Node(int value) : data(value), next(nullptr) {}
}; class CircularQueue {
private: Node* front; // 队列头指针 Node* rear; // 队列尾指针 int count; // 当前队列中的元素数量 public: CircularQueue() : front(nullptr), rear(nullptr), count(0) {} ~CircularQueue() { while (!is_empty()) { dequeue(); } } // 入队操作 void enqueue(int item) { Node* newNode = new Node(item); if (is_empty()) { front = rear = newNode; rear->next = front; // 形成循环 } else { rear->next = newNode; rear = newNode; rear->next = front; // 形成循环 } count++; } // 出队操作 int dequeue() { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } int item = front->data; Node* temp = front; if (front == rear) { // 只有一个元素 front = rear = nullptr; } else { front = front->next; rear->next = front; // 更新尾指针 } delete temp; count--; return item; } // 获取队头元素 int peek() const { if (is_empty()) { std::cout << "Queue is empty!" << std::endl; return -1; // 或抛出异常 } return front->data; } // 检查队列是否为空 bool is_empty() const { return count == 0; } // 获取当前队列大小 int size() const { return count; }
}; int main() { CircularQueue cq; // 创建一个循环队列 cq.enqueue(10); cq.enqueue(20); cq.enqueue(30); std::cout << "Front element: " << cq.peek() << std::endl; // 输出 10 std::cout << "Dequeued: " << cq.dequeue() << std::endl; // 输出 10 std::cout << "Front element after dequeue: " << cq.peek() << std::endl; // 输出 20 cq.enqueue(40); // 尝试入队一个新元素 std::cout << "Front element after enqueue: " << cq.peek() << std::endl; // 输出 20 return 0;
}
四、算法专题
队列是一种重要的数据结构,广泛应用于计算机科学的各个领域。理解队列的基本概念、操作和实现方式对于学习数据结构和算法非常重要。
1.队列的应用场景
任务调度:操作系统中的进程调度。
打印队列:管理打印任务的顺序。
广度优先搜索(BFS):图算法中的节点访问顺序。
消息队列:在分布式系统中传递消息。
2.队列的相关算法
循环队列:通过循环数组或链表实现,避免了空间浪费。
优先队列:每个元素都有一个优先级,出队时优先级高的元素先被移除。
阻塞队列:在多线程环境中使用,支持线程安全的入队和出队操作。
3.算法题推荐
模拟队列:232. 用栈实现队列 - 力扣(LeetCode)
class MyQueue {stack<int> v;
public:MyQueue() {}void push(int x) {v.push(x);}int pop() {if(empty())return NULL;stack<int> ts;while (!v.empty()) {ts.push(v.top());v.pop();}int ans = ts.top();ts.pop();while (!ts.empty()) {v.push(ts.top());ts.pop();}return ans;}int peek() {if(empty())return NULL;stack<int> ts = v;while (ts.size() != 1) {ts.pop();}//就剩栈底了return ts.top();}bool empty() {return v.empty();}
};/*** Your MyQueue object will be instantiated and called as such:* MyQueue* obj = new MyQueue();* obj->push(x);* int param_2 = obj->pop();* int param_3 = obj->peek();* bool param_4 = obj->empty();*/
239. 滑动窗口最大值 - 力扣(LeetCode)双端队列:239. 滑动窗口最大值 - 力扣(LeetCode)
class Solution {
public://时间复杂度:O((n-k)*k)vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> ret;if (nums.size() == 0)return ret;deque<int> q; //存储位置for (int i = 0; i < nums.size(); i++) {while (!q.empty() && nums[i] > nums[q.back()]) {q.pop_back();}q.push_back(i);if (k == i - q.front()) q.pop_front();//超出长度if (i >= k - 1) ret.push_back(nums[q.front()]);}return ret;}
};
优先队列(堆):23. 合并 K 个升序链表 - 力扣(LeetCode)
class Solution {
public:struct Status {int val;ListNode *ptr;bool operator < (const Status &rhs) const {return val > rhs.val;}};priority_queue <Status> q;ListNode* mergeKLists(vector<ListNode*>& lists) {for (auto node: lists) {if (node) q.push({node->val, node});}ListNode head, *tail = &head;while (!q.empty()) {auto f = q.top(); q.pop();tail->next = f.ptr; tail = tail->next;if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next});}return head.next;}
};
感谢大家!
相关文章:
《数据结构》--队列【各种实现,算法推荐】
一、认识队列 队列是一种常见的数据结构,按照先进先出(FIFO,First In First Out)的原则排列数据。也就是说,最早进入队列的元素最先被移除。队列主要支持两种基本操作: 入队(enqueue࿰…...
面试八股文对校招的用处有多大?--GDB篇
前言 1.本系列面试八股文的题目及答案均来自于网络平台的内容整理,对其进行了归类整理,在格式和内容上或许会存在一定错误,大家自行理解。内容涵盖部分若有侵权部分,请后台联系,及时删除。 2.本系列发布内容分为12篇…...
Unity用VS打开FGUI脚本变成杂项怎么处理?
在Unity中使用Visual Studio(VS)打开FGUI脚本时,如果脚本显示为杂项文件,这通常意味着VS没有正确识别或关联这些脚本文件。以下是一些解决此问题的步骤: 对惹,这里有一个游戏开发交流小组,大家…...
交叉熵损失函数(Cross-Entropy Loss Function)解释说明
公式 8-11 的内容如下: L ( y , a ) − [ y log a ( 1 − y ) log ( 1 − a ) ] L(y, a) -[y \log a (1 - y) \log (1 - a)] L(y,a)−[yloga(1−y)log(1−a)] 这个公式表示的是交叉熵损失函数(Cross-Entropy Loss Function)&#…...
和外部机构API交互如何防止外部机构服务不可用拖垮调用服务
引言 在现代的分布式系统和微服务架构中,服务之间的通信往往通过API进行,尤其是在与外部机构或第三方服务进行交互时,更需要通过API实现功能的集成。然而,由于外部服务的可控性较差,其服务的不可用性(如响…...

自动猫砂盆真的有必要吗?买自动猫砂盆不看这四点小心害死猫。
现在越来越多铲屎官选择购买自动猫砂盆来代替自己给猫咪铲屎,可是自动猫砂盆真的有必要吗?要知道,在现在忙碌的生活中,有很多人因为工作上的忙碌而不小心忽视了猫咪,猫咪的猫砂盆堆满粪便,要知道猫砂盆一天…...

国外解压视频素材哪里找?五个海外解压视频素材网站推荐
国外解压视频素材哪里找?五个海外解压视频素材网站推荐 如果你正在寻找国外的解压视频素材,那么今天这篇文章一定能帮助你。无论是修牛蹄、洗地毯,还是切肥皂、玩解压游戏等,下面分享的几个网站都是你找到高质量海外解压视频素材…...

Android一个APP里面最少有几个线程
Android一个APP里面最少有几个线程 参考 https://www.jianshu.com/p/92bff8d6282f https://www.jianshu.com/p/8a820d93c6aa 线程查看 Android一个进程里面最少包含5个线程,分别为: main线程(主线程)FinalizerDaemon线程 终结者守护线程…...

位操作解决数组的花样遍历
文章目录 题目 一、思路: 二、代码 总结 题目 leetcodeT289 https://leetcode.cn/problems/game-of-life/description/ 一、思路: 这题思路很简单,对每个位置按照题目所给规则进行遍历,判断周围网格的活细胞数即可。但是题目要求…...

【面试宝典】深入Python高级:直戳痛点的题目演示(下)
目录 🍔 Python下多线程的限制以及多进程中传递参数的⽅式 🍔 Python是如何进⾏内存管理的? 🍔 Python⾥⾯如何拷⻉⼀个对象? 🍔 Python⾥⾯search()和match()的区别? 🍔 lambd…...

Hive数仓操作(十七)
一、Hive的存储 一、Hive 四种存储格式 在 Hive 中,支持四种主要的数据存储格式,每种格式有其特点和适用场景,不过一般只会使用Text 和 ORC : 1. Text 说明:Hive 的默认存储格式。存储方式:行存储。优点…...
工业和自动化领域常见的通信协议
在工业和自动化领域,有多种常见的通信协议,主要用于设备间的通信、数据传输和控制。 Modbus: 类型:串行通信协议用途:广泛用于工业自动化设备间的通信,如PLC、传感器和执行器。优点:简单、开放且…...

连夜爆肝收藏各大云服务新老用户优惠活动入口地址(内含免费试用1个月的地址),适用于小白,大学生,开发者,小企业老板....
具体请前往:云服务器优惠活动入口大全--收藏各主流云厂商的云服务器等系列产品的优惠活动入口,免费试用1个月活动入口,让新老用户都能根据使用场景和身份快速锁定优惠权益 经济下滑,被优化增多,大学生就业难࿰…...
SpringBoot+Redis+RabbitMQ完成增删改查
各部分分工职责 RabbitMQ负责添加、修改、删除的异步操作 Redis负责数据的缓存 RabbitMQ里面角色职责简单描述 RabbitMQ里面有几个角色要先分清以及他们的对应关系: 交换机、队列、路由键 交换机和队列是一对多 队列和路由键是多对多 然后就是消息的发送者&…...

【系统集成中级】线上直播平台开发项目质量管理案例分析
【系统集成中级】线上直播平台开发项目质量管理案例分析 一、案例二、小林在项目质量管理中存在的问题(一)计划阶段缺失(二)测试用例编制与执行问题(三)质量管理流程问题(四)质量保证…...

浪潮信息领航边缘计算,推动AI与各行业深度融合
在9月20日于安徽盛大召开的浪潮信息边缘计算合作伙伴大会上,浪潮信息指出,未来的计算领域将全面融入AI技术,特别是在企业边缘侧,智能应用特别是生成式人工智能应用正在迅速普及,这一趋势正引领边缘计算向边缘智算的方向…...

Koa2项目实战3 (koa-body,用于处理 HTTP 请求中的请求体)
以用户注册接口为例,需要在请求里携带2个参数:用户名(user_name)和密码(password)。 开发者需要在接口端,解析出user_name 、password。 在使用Koa开发的接口中,如何解析出请求携带…...
复盘20241012
1、 classpath "com.android.tools.build:gradle:8.5.1" 的版本 与distributionUrlhttps\://services.gradle.org/distributions/gradle-8.9-bin.zip的对应规则: Execution failed for task :app:compileDebugKotlin. 解决方案 切换 setting --> ot…...
泊松流负载均衡控制
目录 泊松流负载均衡控制 一、到达率λ 二、服务率μ 三、泊松流负载均衡控制 泊松流负载均衡控制 在探讨泊松流负载均衡控制时,我们主要关注的是到达率λ和服务率μ这两个核心参数。以下是对这两个参数及其在泊松流负载均衡控制中作用的详细解释: 一、到达率λ 定义:…...

3D打印矫形器市场报告:未来几年年复合增长率CAGR为10.8%
3D 打印矫形器是指使用 3D 打印技术制作的定制外部支撑装置。它们有助于稳定、引导、缓解或纠正肌肉骨骼状况,并根据个体患者的解剖结构进行设计,通常使用 3D 扫描和建模技术。3D 打印在矫形器方面的主要优势是能够生产精确适合患者解剖结构的定制装置&a…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...