《数据结构》--队列【各种实现,算法推荐】

一、认识队列

队列是一种常见的数据结构,按照先进先出(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;}
};


感谢大家! 

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

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

相关文章

【微信小程序_9_WXSS模板样式】

摘要:本文主要介绍了微信小程序开发中的 WXSS。WXSS 类似于网页开发中的 CSS,具有其大部分特性同时又有扩展,如 rpx 尺寸单位、@import 样式导入等。其中 rpx 是解决屏适配的独特单位,有特定实现原理和不同设备的换算方式。@import 可导入外联样式表,有明确语法格式和示例…

爬虫设计思考之二

“所谓爬虫,其本质是一种计算机程序,它的行为看起来就像是蜘蛛在网上面爬行一样,顺着互联网这个“网”,一条线一条线地“爬行”。 一、认识爬虫 爬虫这个词对于非专业人士比较的陌生&#xff0c;但是实际却和我们的生活息息相关。例如我们国内经常使用的百度浏览器搜索&#x…

线性代数 行列式

一、行列式 1、定义 一个数学概念&#xff0c;主要用于 线性代数中&#xff0c;它是一个可以从方阵&#xff08;即行数和列数相等的矩阵&#xff09;形成的一个标量&#xff08;即一个单一的数值&#xff09; 2、二阶行列式 &#xff0c;像这样将一个式子收缩称为一个 2*2 的…

【数据结构】【链表代码】移除链表元素

移除链表元素 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val) { // 创建一个虚拟头节点&#xff0c;以处理头节点可能被删除的情况 struct…

【mysql 截断订单表order 报错】

truncate table order;这个是一个截断订单表的sql语句 看起来没有什么问题 但是实际执行的时候是会报错的 SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version…

27-云计算下一个十年技术Serverless

├──27-云计算下一个十年技术Serverless | ├──1-Serverless深度实战之Knative | | ├──1-使用Knative平台环境说明 | | ├──2-现阶段云原生应用领域介绍 | | ├──3-为什么要引入Serverless | | ├──4-Serverless应用场景 | | ├──5-Serve…

4. 单例模式线程安全问题--是否加锁

单例模式线程安全问题--是否加锁 是否加锁问题指什么&#xff1f;解决多线程并发来带的问题继承MonoBehaviour的单例模式不继承MonoBehaviour的单例模式 总结 是否加锁问题指什么&#xff1f; 如果程序当中存在多线程&#xff0c;我们需要考虑当多个线程同时访问同一个内存空间…

计算机毕业设计 内蒙古旅游景点数据分析系统的设计与实现 Python毕业设计 Python毕业设计选题 Spark 大数据【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

筛斗数据:如何提高数据治理的安全性

提高数据治理的安全性是一个多层次、多维度的任务&#xff0c;涉及技术、管理、法律等多个方面。以下是一些具体的策略和建议&#xff1a; 一、技术层面 数据加密&#xff1a;采用先进的加密算法对敏感数据进行加密存储和传输&#xff0c;确保数据在各个环节中的安全性。这包…

element-plus组件之Upload(2.0)

接上篇 下面的属性就对应着回调函数&#xff0c;下面就一一进行介绍。 因为element-plus在封装upload组件时就自带了一个预览和删除的图标&#xff0c;只是没有方法实现&#xff0c;这里进行指明。 就是在图片墙列表中&#xff0c;自动就带了这两个图标和遮罩&#xff0c;下面…

pip安装指定版本的tensorflow

安装CPU版本&#xff1a;(以2.9.0版本为例) pip install tensorflow2.9.0安装GPU版本&#xff1a;(以2.9.0版本为例) pip install tensorflow-gpu2.9.0若下载缓慢&#xff0c;使用阿里国内镜像源加速下载&#xff1a;(以2.9.0版本为例) pip install -i https://mirrors.aliy…

[C#]使用纯opencvsharp部署yolov11-onnx图像分类模型

【官方框架地址】 https://github.com/ultralytics/ultralytics.git 【算法介绍】 使用纯OpenCvSharp部署YOLOv11-ONNX图像分类模型是一项复杂的任务&#xff0c;但可以通过以下步骤实现&#xff1a; 准备环境&#xff1a;首先&#xff0c;确保开发环境已安装OpenCvSharp和必…

人脸识别face-api.js应用简介

前阵子学习了一下face-api.js &#xff0c;偶有心得&#xff0c;跟大家分享一下。 face-api.js的原始项目是https://github.com/justadudewhohacks/face-api.js &#xff0c;最后一个release是2020年3月22日的0.22.2版&#xff0c;组件较老&#xff0c;API文档很全&#xff0c;…

鸿蒙网络管理模块07——网络质量管理

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 HarmonyOS提供了一套网络网络质量管理的套件&#xff08;Network Boost Ki…

[论文笔记]DAPR: A Benchmark on Document-Aware Passage Retrieval

引言 今天带来论文DAPR: A Benchmark on Document-Aware Passage Retrieval的笔记。 本文提出了一个基准&#xff1a;文档感知段落检索(Document-Aware Passage Retrieval,DAPR)以及介绍了一些上下文段落表示的方法。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c…

麒麟信安CentOS安全加固案例获评中国信通院第三届“鼎新杯”数字化转型应用奖

“鼎新杯”数字化转型应用大赛&#xff0c;由中国通信标准化协会主办、中国信息通信研究院承办&#xff0c;以落实国家“十四五”规划关于“加快数字化发展&#xff0c;建设数字中国”的总体要求为目标&#xff0c;意在打造一批具有产业引领与推广应用效应的企业数字化转型应用…

conda打包

tar 是一个在 Unix 和类 Unix 系统中常用的命令行工具&#xff0c;用于打包多个文件和目录到一个归档文件&#xff08;通常称为 tarball&#xff09;&#xff0c;以及从这些归档文件中解包文件和目录。 以下是使用 tar 进行打包和解包的基本用法&#xff1a; 打包&#xff08;…

OCR+PDF解析配套前端工具开源详解!

目录 一、项目简介 TextIn为相关领域的前端开发提供了优秀的范本。 目前项目已在Github上开源&#xff01; 二、性能特色 三、安装使用 安装依赖启动项目脚本命令项目结构 四、效果展示 面对日常生活和工作中常见的OCR识别、PDF解析、翻译、校对等场景&#xff0c;配套的…

【C++进阶】set的使用

1. 序列式容器和关联式容器 前面&#xff0c;我们已经接触过STL中的部分容器如&#xff1a;string、vector、list、deque、array、forward_list等&#xff0c;这些容器统称为序列式容器&#xff0c;因为逻辑结构为线性序列的数据结构&#xff0c;两个位置存储的值之间⼀般没有紧…

dvwa:暴力破解、命令注入、csrf全难度详解

暴力破解 easy模式 hydra -L /usr/share/wordlists/SecLists-master/Usernames/top-usernames-shortlist.txt -P /usr/share/wordlists/SecLists-master/Passwords/500-worst-passwords.txt 192.168.72.1 http-get-form "/dvwa/vulnerabilities/brute/:username^USER^&…