《数据结构》--队列【各种实现,算法推荐】
一、认识队列
队列是一种常见的数据结构,按照先进先出(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…...

Richtek立锜科技线性稳压器 (LDO) 选型
一、什么是LDO? LDO也可称为低压差线性稳压器,适合从较高的输入电压转换成较低输出电压的应用,这种应用的功率消耗通常不是很大,尤其适用于要求低杂讯、低电流和输入、输出电压差很小的应用环境。 二、LDO的特性 LDO透过控制线性区调整管…...

Leetcode 前 k 个高频元素
使用最小堆算法来解决这道题目:相当于有一个容量固定为K的教室,只能容纳 K 个人,学生们逐个逐个进入该教室,当教室容量达到K人之后,每次进入一个新的学生后,我们将分数最低的学生(类似本题中的频率最低元素…...

[LeetCode] 面试题01.02 判定是否互为字符重拍
题目描述: 给定两个由小写字母组成的字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。 示例 1: 输入: s1 "abc", s2 "bca" 输出: true 示例 2&am…...

数据结构-4.5.KMP算法(旧版上)-朴素模式匹配算法的优化
朴素模式匹配算法最坏的情况: 一.实例: 第一轮匹配失败,开始下一轮的匹配: 不断的操作,最终匹配成功: 如上述图片所述,朴素模式匹配算法会导致时间开销增加, 优化思路:主…...

STM32 QSPI接口驱动GD/W25Qxx配置简要
STM32 QSPI接口GD/W25Qxx配置简要 📝本篇会具体涉及介绍Winbond(华邦)和GD(兆易创新) NOR flash相关型号指令差异。由于网络上可以搜索到很多相关QSPI相关知识内容,不对QSPI通讯协议做深度解析。 🔖首先确保所使用的ST…...

UCI-HAR数据集深度剖析:训练仿真与可视化解读
在本篇文章中,我们将深入探讨如何使用Python对UCI人类活动识别(HAR)数据集进行分割和预处理,以及运用模型网络CNN对数据集进行训练仿真和可视化解读。 一、UCI-HAR数据集分析及介绍 UCI-HAR数据集是一个公开的数据集,…...

牛客SQL练习详解 06:综合练习
牛客SQL练习详解 06:综合练习 SQL34 统计复旦用户8月练题情况SQL35 浙大不同难度题目的正确率SQL39 21年8月份练题总数 叮嘟!这里是小啊呜的学习课程资料整理。好记性不如烂笔头,今天也是努力进步的一天。一起加油进阶吧! SQL34 统…...

k8s apiserver高可用方案
目前官方推荐有 2 种方式部署k8s apiserver 高可用 keepalived and haproxy 部署有2种方式,一种是systemd管理的,另一种是pod形式,使用那种可以根据实际情况选择 服务部署 systemd方式 可以通过包管理工具安装,正常启动之后&…...

服务器数据恢复—硬盘坏扇区导致Linux系统服务器数据丢失的数据恢复案例
服务器数据恢复环境: 一台linux操作系统网站服务器,该服务器上部署了几十个网站,使用一块SATA硬盘。 服务器故障&原因: 服务器在工作过程中突然宕机。管理员尝试重新启动服务器失败,于是将服务器上的硬盘拆下检测…...

【多线程】多线程(12):多线程环境下使用哈希表
【多线程环境下使用哈希表(重点掌握)】 可以使用类:“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁,就是直接给put,get等方法加上synch…...