C++笔记之环形队列

C++笔记之环形队列

code review!

文章目录

  • C++笔记之环形队列
    • 1.概念I——摘自 https://mp.weixin.qq.com/s/HUn9TF09RZ-UJKYPR5ZXhA
    • 2.概念II——摘自 http://t.csdnimg.cn/72bng
    • 3.概念III—— 摘自https://mp.weixin.qq.com/s/9Ga502p1DLcc6o75JBQlDg
    • 4.概念IV—— 摘自https://mp.weixin.qq.com/s/pJaIlUrZoEmLzWJfP2Nyyw
    • 5.一种更好的计算队尾指针的方法—— 摘自https://mp.weixin.qq.com/s/g2WBerFa0MaAsounduG43A
    • 6.环形队列中读写使用索引和指针的比较
    • 7.例:使用数组实现一个简单的环形队列
    • 8.例:使用vector实现一个简单的环形队列
    • 9.C++使用环形队列实现一个完整的生产者-消费者简单例程

1.概念I——摘自 https://mp.weixin.qq.com/s/HUn9TF09RZ-UJKYPR5ZXhA

在这里插入图片描述

  • 1、数组构造环形缓冲区
    在这里插入图片描述

  • 2、向环形缓冲区写入3个数据
    在这里插入图片描述

  • 3、从环形缓冲区读取2个数据
    在这里插入图片描述

  • 4、再写入3个数据
    在这里插入图片描述

  • 5、再写入1个数据
    在这里插入图片描述

  • 6、代码实现

/* 实现的最简单的ringbuff 有更多提升空间,可以留言说明 */
#include "stdio.h"
#include "stdlib.h"#define LEN 10/*环形队列结构体*/
typedef struct ring_buff{int array[LEN];int W;int R;
}*ring;/*环形队列初始化*/
struct ring_buff * fifo_init(void)
{struct ring_buff * p = NULL;p = (struct ring_buff *)malloc(sizeof(struct ring_buff));if(p == NULL){printf("fifo_init malloc error\n");return NULL;}p->W = 0;p->R = 0;return p;
}/*判断环形队列是否已经满了*/
int get_ring_buff_fullstate(struct ring_buff * p_ring_buff)
{/*如果写位置减去读位置等于队列长度,就说明这个环形队列已经满*/if((p_ring_buff->W - p_ring_buff->R) == LEN){return (1);}else{return (0);}
}/*判断环形队列为空*/
int get_ring_buff_emptystate(struct ring_buff * p_ring_buff)
{/*如果写位置和读的位置相等,就说明这个环形队列为空*/if(p_ring_buff->W == p_ring_buff->R){return (1);}else{return (0);}
}
/*插入数据*/
int ring_buff_insert(struct ring_buff * p_ring_buff,int data)
{if(p_ring_buff == NULL){printf("p null\n");return (-1);	}if(get_ring_buff_fullstate(p_ring_buff) == 1){printf("buff is full\n");return (-2);}p_ring_buff->array[p_ring_buff->W%LEN] = data;p_ring_buff->W ++;//printf("inset:%d %d\n",data,p_ring_buff->W);return (0);
}/*读取环形队列数据*/
int ring_buff_get(struct ring_buff * p_ring_buff)
{int data = 0;if(p_ring_buff == NULL){printf("p null\n");return (-1);	}if(get_ring_buff_emptystate(p_ring_buff) == 1){printf("buff is empty\n");return (-2);}data = p_ring_buff->array[p_ring_buff->R%LEN];p_ring_buff->R++;return data;
}/*销毁*/
int ring_buff_destory(struct ring_buff * p_ring_buff)
{if(p_ring_buff == NULL){printf("p null\n");return (-1);	}free(p_ring_buff);return (0);
}int main()
{int i = 0;/*定义一个环形缓冲区*/ring pt_ring_buff = fifo_init();/*向环形缓冲区中写入数据*/for(i = 0;i<10;i++){ring_buff_insert(pt_ring_buff,i);}/*从环形缓冲区中读出数据*/for(i = 0;i<10;i++){printf("%d ",ring_buff_get(pt_ring_buff));}/*销毁一个环形缓冲区*/ring_buff_destory(pt_ring_buff);return (1);
}

运行
在这里插入图片描述

2.概念II——摘自 http://t.csdnimg.cn/72bng

在这里插入图片描述

3.概念III—— 摘自https://mp.weixin.qq.com/s/9Ga502p1DLcc6o75JBQlDg

在这里插入图片描述

  • 实现环形队列图示过程

    1. 初始化一个数组大小为6的环形队列, 头指针front=0, 尾指针rear=0, 刚好front=rear =0的状态,表示环形队列为空.
      在这里插入图片描述
    1. 向环形队列里插入1个元素,则rear指针移动一格,front=0,rear=1
      在这里插入图片描述
  • 3.继续添加a2,a3,a4,a5元素,rear指针指到末尾处,front=0, reat=5
    在这里插入图片描述

  • 4.如果再继续添加a6元素,则rear=6,大于数组大小,发生数组溢出.
    在这里插入图片描述

  • 5.如上图所示添加a6时,rear指针发生溢出.我们使用一个小技巧,当rear=6时与数组大小6进行取模, (rear+1) % maxLen,让rear指针回到开始处rear=0,问题来了,我们无法判断数组是否满?因为初始化时front=rear=0, 现在数组满也是front=rear=0
    在这里插入图片描述

  • 6.解决以上问题有三种办法,我们采用第3种方法实现.
    在这里插入图片描述

使用第3种方法: 即当(rear+1) % maxLen == front时,判断环形数组满,则无法添加元素
在这里插入图片描述

在这里插入图片描述

4.概念IV—— 摘自https://mp.weixin.qq.com/s/pJaIlUrZoEmLzWJfP2Nyyw

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

头指针和尾指针指向同一个位置代表当前队列为空,当前环形队列不能将数据插满,如果插满则无法判断队列为空的情况。所以最后一个位置要空出来,不插入值。判定队列满的情况则是用尾指针的下一个指针指向头则说明当前环形队列已满。

5.一种更好的计算队尾指针的方法—— 摘自https://mp.weixin.qq.com/s/g2WBerFa0MaAsounduG43A

在这里插入图片描述

6.环形队列中读写使用索引和指针的比较

在C++中实现环形队列时,可以使用索引或指针来表示读和写的位置,具体取决于你的实现方式和个人偏好。以下是两种常见的方法:

  1. 使用索引:
    在这种方法中,你可以使用两个索引来表示队列的读和写位置。一个索引表示队列的头部,另一个表示队列的尾部。当元素被入队时,尾部索引递增;当元素被出队时,头部索引递增。当索引到达队列的末尾时,可以通过取模运算将其重置为队列的开头,以实现环形队列的特性。
   int queue[MAX_SIZE];  // 假设队列的最大大小是MAX_SIZEint front = 0;        // 头部索引int rear = 0;         // 尾部索引// 入队操作void enqueue(int item) {if ((rear + 1) % MAX_SIZE == front) {// 队列已满cout << "队列已满,无法入队" << endl;return;}queue[rear] = item;rear = (rear + 1) % MAX_SIZE;}// 出队操作int dequeue() {if (front == rear) {// 队列为空cout << "队列为空,无法出队" << endl;return -1;  // 返回一个特定的错误值或抛出异常}int item = queue[front];front = (front + 1) % MAX_SIZE;return item;}
  1. 使用指针:
    另一种方法是使用指针来表示队列的读和写位置。你可以使用两个指针,一个指向队列的头部,另一个指向队列的尾部。入队和出队操作会移动这些指针,并确保它们在环形队列中正确移动。
   int queue[MAX_SIZE];  // 假设队列的最大大小是MAX_SIZEint *front = queue;   // 头部指针int *rear = queue;    // 尾部指针// 入队操作void enqueue(int item) {if ((rear + 1) % MAX_SIZE == front) {// 队列已满cout << "队列已满,无法入队" << endl;return;}*rear = item;rear = (rear + 1) % MAX_SIZE;}// 出队操作int dequeue() {if (front == rear) {// 队列为空cout << "队列为空,无法出队" << endl;return -1;  // 返回一个特定的错误值或抛出异常}int item = *front;front = (front + 1) % MAX_SIZE;return item;}

横向排版对比
在这里插入图片描述

无论你选择使用索引还是指针,都可以实现一个有效的环形队列。选择哪种方式取决于你的偏好和实际需求。指针的方法在某些情况下可能更直观,因为你可以像操作普通数组一样操作指针,而无需进行索引运算。但索引方法也是常见的,因为它们更容易理解和实现。

7.例:使用数组实现一个简单的环形队列

在这里插入图片描述

代码

#include <iostream>const int MAX_SIZE = 10;  // 假设队列的最大大小是10class CircularQueue {
private:int queue[MAX_SIZE];  // 队列数组int front;            // 头部索引int rear;             // 尾部索引public:CircularQueue() {front = -1;rear = -1;}// 判断队列是否为空bool isEmpty() {return front == -1 && rear == -1;}// 判断队列是否已满bool isFull() {return (rear + 1) % MAX_SIZE == front;}// 入队操作void enqueue(int item) {if (isFull()) {std::cout << "队列已满,无法入队" << std::endl;return;}if (isEmpty()) {front = rear = 0;} else {rear = (rear + 1) % MAX_SIZE;}queue[rear] = item;}// 出队操作int dequeue() {if (isEmpty()) {std::cout << "队列为空,无法出队" << std::endl;return -1;  // 返回一个特定的错误值或抛出异常}int item = queue[front];if (front == rear) {front = rear = -1;  // 队列中只有一个元素时的特殊情况} else {front = (front + 1) % MAX_SIZE;}return item;}
};int main() {CircularQueue q;q.enqueue(1);q.enqueue(2);q.enqueue(3);std::cout << "Dequeued: " << q.dequeue() << std::endl;std::cout << "Dequeued: " << q.dequeue() << std::endl;std::cout << "Dequeued: " << q.dequeue() << std::endl;q.enqueue(4);q.enqueue(5);std::cout << "Dequeued: " << q.dequeue() << std::endl;std::cout << "Dequeued: " << q.dequeue() << std::endl;return 0;
}

运行

Dequeued: 1
Dequeued: 2
Dequeued: 3
Dequeued: 4
Dequeued: 5

8.例:使用vector实现一个简单的环形队列

在这里插入图片描述

代码

#include <iostream>
#include <vector>class CircularQueue {
private:std::vector<int> queue;int front;int rear;int maxSize;public:CircularQueue(int size) : maxSize(size) {queue.resize(size);front = -1;rear = -1;}bool isEmpty() {return front == -1 && rear == -1;}bool isFull() {return (rear + 1) % maxSize == front;}void enqueue(int item) {if (isFull()) {std::cout << "队列已满,无法入队" << std::endl;return;}if (isEmpty()) {front = rear = 0;} else {rear = (rear + 1) % maxSize;}queue[rear] = item;}int dequeue() {if (isEmpty()) {std::cout << "队列为空,无法出队" << std::endl;return -1; // 返回一个特定的错误值或抛出异常}int item = queue[front];if (front == rear) {front = rear = -1;} else {front = (front + 1) % maxSize;}return item;}
};int main() {CircularQueue q(10);q.enqueue(1);q.enqueue(2);q.enqueue(3);std::cout << "Dequeued: " << q.dequeue() << std::endl;std::cout << "Dequeued: " << q.dequeue() << std::endl;std::cout << "Dequeued: " << q.dequeue() << std::endl;q.enqueue(4);q.enqueue(5);std::cout << "Dequeued: " << q.dequeue() << std::endl;std::cout << "Dequeued: " << q.dequeue() << std::endl;return 0;
}

运行

Dequeued: 1
Dequeued: 2
Dequeued: 3
Dequeued: 4
Dequeued: 5

9.C++使用环形队列实现一个完整的生产者-消费者简单例程

在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>const int bufferSize = 5; // 缓冲区大小class CircularQueue {public:CircularQueue() : buffer(bufferSize), front(0), rear(0), count(0) {}// 生产者线程使用的enqueue函数,将数据添加到队列void enqueue(int item) {std::unique_lock<std::mutex> lock(mutex);// 检查队列是否已满if (count < bufferSize) {buffer[rear] = item;rear = (rear + 1) % bufferSize;count++;std::cout << "Produced: " << item << std::endl;// 通知等待中的消费者线程有新数据可用cv.notify_all();}}// 消费者线程使用的dequeue函数,从队列中取出数据int dequeue() {std::unique_lock<std::mutex> lock(mutex);// 如果队列为空,等待生产者生产数据while (count == 0) {cv.wait(lock);}// 从队列中取出数据int item = buffer[front];front = (front + 1) % bufferSize;count--;std::cout << "Consumed: " << item << std::endl;return item;}private:std::vector<int> buffer;    // 缓冲区,用于存储数据int front;                  // 队列前部索引int rear;                   // 队列后部索引int count;                  // 当前队列中的元素数量std::mutex mutex;           // 用于线程同步的互斥锁std::condition_variable cv; // 条件变量,用于线程等待和通知
};// 生产者线程函数,负责向队列中添加数据
void producer(CircularQueue &queue) {for (int i = 1; i <= 10; ++i) {queue.enqueue(i);// 模拟生产耗时std::this_thread::sleep_for(std::chrono::milliseconds(200));}
}// 消费者线程函数,负责从队列中取出数据
void consumer(CircularQueue &queue) {for (int i = 0; i < 10; ++i) {int item = queue.dequeue();// 模拟消费耗时std::this_thread::sleep_for(std::chrono::milliseconds(300));}
}int main() {CircularQueue queue;// 创建生产者线程和消费者线程std::thread producerThread(producer, std::ref(queue));std::thread consumerThread(consumer, std::ref(queue));// 等待线程结束producerThread.join();consumerThread.join();return 0;
}

运行
在这里插入图片描述

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

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

相关文章

基于SSM的网上药品售卖系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Django之模板

一&#xff09;模板&#xff08;T&#xff09; 什么时候会使用模板呢&#xff1f; 仅对于Django这个框架来说&#xff0c;因为其是默认前后端不分离的框架&#xff08;前后端不分离值开发时前后端的代码在一起&#xff0c;不通过接口的方式连接&#xff0c;通过模板渲染的方式…

Ubuntu 20.04 安装部署 TiDB DM v7.3.0 集群【全网独家】

文章目录 测试环境说明TiDB 单机环境部署DM 集群部署1. 免密设置2. 组件下载3. DM 配置文件模板获取4.DM 配置文件设置5.部署与启动 DM 集群 前言&#xff1a; 放眼全网&#xff0c;我找不出一篇在 Ubuntu 里面搭建 DM 集群的文章&#xff0c;虽然 TiDB 官方推荐使用 CentOS 系…

多线程 - 阻塞式队列

阻塞队列 阻塞队列,也是一个队列 ~~ 先进先出 实际上有一些特殊的队列,不一定非得遵守先进先出的 ~~ 优先级队列(PriorityQueue) 阻塞队列,也是特殊的队列,虽然也是先进先出的,但是带有特殊的功能: 阻塞 如果队列为空,执行出队列操作,就会阻塞.阻塞到另一个线程往队列里添加元…

gitee 远程仓库操作基础(二)

(1&#xff09;clone远端仓库,本地建立分支推送 (基于远程仓库版本库 本地建立分支开发新功能) git clone gitgitee.com:xxxxx/alsa_test.git git remote add origin gitgitee.com:xxxxx/alsa_test.git进入clone过后路径代码,查看本地分支,发现该项目远程仓库有很多分支 基于…

分布式文件存储系统Minio实战

分布式文件系统应用场景 互联网海量非结构化数据的存储需求电商网站&#xff1a;海量商品图片视频网站&#xff1a;海量视频文件网盘 : 海量文件社交网站&#xff1a;海量图片 1. Minio介绍 MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存…

【JVM】第四篇 垃圾收集器ParNewCMS底层三色标记算法详解

导航 一. 垃圾收集算法详解1. 分代收集算法2. 标记-复制算法3. 标记-清除算法4. 标记-整理算法二. 垃圾收集器详解1. Serial收集器2. Parallel Scavenge收集器3. ParNew收集器4. CMS收集器三. 垃圾收集底层三色标记算法实现原理1. 垃圾收集底层使用三色标记算法的原因?2. 垃圾…

[Linux 基础] 一篇带你了解linux权限问题

文章目录 1、Linux下的两种用户2、文件类型和访问权限&#xff08;事物属性&#xff09;2.1 Linux下的文件类型2.2 基本权限2.3 文件权限值的表示方法&#xff08;1&#xff09;字符表示方法&#xff08;2&#xff09;8进制数值表示方法 2.4 文件访问权限的相关设置方法(1) chm…

javaee SpringMVC中json的使用

jsp <%--Created by IntelliJ IDEA.User: 呆萌老师:QQ:2398779723Date: 2019/12/6Time: 15:55To change this template use File | Settings | File Templates. --%> <% page contentType"text/html;charsetUTF-8" language"java" %> <%St…

json能够存储图片吗?

JSON 本身并不适合存储图片&#xff0c;因为它是一种轻量级的数据交换格式&#xff0c;易于阅读和编写&#xff0c;同时也易于机器解析和生成。JSON 数据格式简单&#xff0c;只包含键值对&#xff0c;因此它主要用于存储和传输文本数据。 然而&#xff0c;你可以将图片转换为 …

《数据结构、算法与应用C++语言描述》-栈的应用-列车车厢重排问题

列车车厢重排问题 一列货运列车有 n 节车厢&#xff0c;每节车厢要停靠在不同的车站。假设 n个车站从 1 到n 编号&#xff0c;而且货运列车按照从n到1的顺序经过车站。车厢的编号与它们要停靠的车站编号相同。为了便于从列车上卸掉相应的车厢&#xff0c;必须按照从前至后、从…

【吞噬星空】连播两集,尼赫鲁对徐欣动手,罗峰修分身强势复仇

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析吞噬星空资讯。 吞噬星空动画第四季定档之后&#xff0c;官方真的是太宠粉了&#xff0c;每天都会公布全新预告情报&#xff0c;无论是外星人物角色&#xff0c;亦或者宇宙星球建模&#xff0c;那都是相当的炸裂。如今更…

Leetcode 450. 删除二叉搜索树中的节点

文章目录 题目代码&#xff08;10.2 首刷看解析&#xff09; 题目 Leetcode 450. 删除二叉搜索树中的节点 代码&#xff08;10.2 首刷看解析&#xff09; class Solution { public:TreeNode* deleteNode(TreeNode* root, int key) {if(!root)return root;if(root->val <…

Apache Derby的使用

Apache Derby是关系型数据库&#xff0c;可以嵌入式方式运行&#xff0c;也可以独立运行&#xff0c;当使用嵌入式方式运行时常用于单元测试&#xff0c;本篇我们就使用单元测试来探索Apache Derby的使用 一、使用IDEA创建Maven项目 打开IDEA创建Maven项目&#xff0c;这里我…

1、【开始】【简介】Qlib:量化平台

【简介】1、Qlib:量化平台 简介框架简介 Qlib是一个面向AI的量化投资平台,旨在实现AI技术在量化投资中的潜力,赋能研究,并创造价值。 通过Qlib,用户可以轻松利用他们的想法来创建更好的量化投资策略。 框架 在模块层,Qlib 是由上述组件组成的平台。这些组件被设计为低耦…

1.基本概念 进入Java的世界

1.1 Java的工作方式 1.2 Java的程序结构 类存于源文件里面&#xff0c;方法存于类中&#xff0c;语句&#xff08;statement&#xff09;存于方法中 源文件&#xff08;扩展名为.java&#xff09;带有类的定义。类用来表示程序的一个组件&#xff0c;小程序或许只会有一个类…

Flutter笔记:手写一个简单的画板工具

Flutter笔记 手写一个简单的画板工具 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133418742 目 录 1…

localStorage实现历史记录搜索功能

&#x1f4dd;个人主页&#xff1a;爱吃炫迈 &#x1f48c;系列专栏&#xff1a;JavaScript &#x1f9d1;‍&#x1f4bb;座右铭&#xff1a;道阻且长&#xff0c;行则将至&#x1f497; 文章目录 为什么使用localStorage如何使用localStorage实现历史记录搜索功能&#xff08…

shell脚本学习笔记

shell脚本重点记录 判断文件或者文件夹是否存在 if [ ! -d "log" ];thenchmod 707 $file1一个文件的权限包括读取、写入、执行&#xff0c;权限范围包含所有者、所属组、其他人&#xff0c;可以通过数字或者字母描述一个文件的权限&#xff1a;读取权限对应r或4&a…

【办公自动化】在Excel中按条件筛选数据并存入新的表(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…