C++笔记之环形队列

news2024/11/26 21:38:15

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_SIZE
   int 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_SIZE
   int *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;  // 假设队列的最大大小是10

class 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.coloradmin.cn/o/1056223.html

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

相关文章

Scala第十三章节

Scala第十三章节 1. 高阶函数介绍 2. 作为值的函数 3. 匿名函数 4. 柯里化 5. 闭包 6. 控制抽象 7. 案例: 计算器 scala总目录 文档资料下载

面试打底稿⑦ 项目一的第三部分

简历原文 抽查部分 完成路线规划模块选择路线功能&#xff0c;用neo4j这种存储图关系的非关系数据库&#xff0c;实现最短线路规划、最低成本线路规划 设计优化物流信息模块&#xff0c;合理选择数据库、缓存技术&#xff0c;实现数据精简、流量削峰、提高系统可 用性 模拟问答…

2023(2024届)计算机保研经验分享,圆梦山东大学

前言&#xff1a; Hello大家好&#xff0c;我是Dream&#xff0c;好久不见啦&#xff01;在这不见的半年多时间里我一直在全身心的投入保研之中&#xff0c;在写下这份面经时&#xff0c;真的是感慨颇多&#xff0c;思绪万千。站在这个时间点上&#xff0c;回首过去的几个月&am…

汽车电子——产品标准规范汇总和梳理(控制器)

文章目录 前言 一、电机控制 二、转向控制 三、制动控制 四、电池管理系统 五、充电系统 六、车身系统 七、通讯系统 总结 前言 见《汽车电子——产品标准规范汇总和梳理》 一、电机控制 《GB/T 18488.1-201X 电动汽车用电机及其控制器 第1部分&#xff1a;技术条件…

数字IC前端学习笔记:数字乘法器的优化设计(阵列乘法器)

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 数字信号处理作为微处理器的核心部件&#xff0c;是决定着总体处理器性能的因素之一&#xff0c;而数字乘法器是最常见的一种数字信号处理电路。通常情况下&#…

AMBA总线APB、AHB、AXI(详细)总结附实例便于快速掌握

目录 一、简介二、具体内容2.1 APB2.2 AHB2.3 AXI 三、总线对比3.1 总体对比3.2 部分功能差异 四、其他相关链接1、PCI总线及发展历程总结2、SPI协议详细总结附实例图文讲解通信过程3、I2C总线内容总结分享 一、简介 本文主要介绍APB、AHB和AXI总线的相关内容&#xff0c;同时…

初级篇—第一章初识数据库

文章目录 为什么要使用数据库数据库与数据库管理系统数据库的相关概念数据库与数据库管理系统的关系 常用的数据库为什么如此多的厂商要选用MySQL&#xff1f;MySQL的目录 RDBMS 与 非RDBMS关系型数据库(RDBMS)非关系型数据库(非RDBMS) 关系型数据库设计规则表、记录、字段表的…

力扣:117. 填充每个节点的下一个右侧节点指针 II(Python3)

题目&#xff1a; 给定一个二叉树&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NULL 。 初始状态下&#xff0c;所…

Springboot+vue的在线试题题库管理系统(有报告),Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的在线试题题库管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的在线试题题库管理系统&#xff0c;采用M&…

代码随想录算法训练营第五十二天 | 300. 最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

1. 最长递增子序列 300. 最长递增子序列 - 力扣&#xff08;LeetCode&#xff09; dp[i] 取决于 i 之前所有的dp class Solution {public int lengthOfLIS(int[] nums) {// dp[i] 第 0 - i 位的递增子序列长度int length nums.length;int[] dp new int[length];Arrays.fil…

基于 jasypt 实现spring boot 配置文件脱敏

前言 在项目构建过程中&#xff0c;保护敏感信息的安全性至关重要&#xff0c;为了提高系统的安全性能&#xff0c;我们采用了Jasypt来对配置文件中的敏感信息进行加密处理&#xff0c;以确保系统的机密信息不被轻易泄露。 步骤 添加Maven依赖 首先&#xff0c;我们需要添加…

秋招校招,什么是群面?

时间已经来到十月份&#xff0c;我们也迎来了秋季招聘的高峰期。一般来说&#xff0c;企业为了提高面试的速度&#xff0c;一般都会让我们进行群面。可是&#xff0c;很多人不懂得“群面”的意思&#xff0c;由此导致自己在面试环节丢分。今天&#xff0c;就跟着小编一起来了解…

Maven下载源码出现:Cannot download sources Sources not found for org.springframwork...

Maven下载源码出现&#xff1a;Cannot download sources Sources not found for org.springframwork… 最近重装了IDEA再次查看源码时发现总是报错&#xff0c;网上找了很多&#xff0c;发现解决方法都是在项目终端执行如下命令&#xff1a; mvn dependency:resolve -Dclassi…

【面试经典150 | 矩阵】矩阵置零

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a; O ( m n ) O(mn) O(mn) 空间复杂度方法二&#xff1a; O ( m n ) O(mn) O(mn) 空间复杂度方法三&#xff1a;仅使用2个额外变量的常量空间复杂度 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算…

网络工程师对口的岗位是什么

大家好&#xff0c;我是网络工程师成长日记实验室的郑老师&#xff0c;您现在正在查看的是网络工程师成长日记专栏&#xff0c;记录网络工程师日常生活的点点滴滴 网络工程师可以从事哪些职位呢&#xff1f;其实网络工程师最对应的最对口的这个岗位就是高级网络工程师、系统集成…

Centos一键安装、切换各版本JDK

查看服务中的安装的jdk rpm -qa | grep java获取jdk各版本信息 yum -y list java*查看指定版本 yum -y list java*|grep 1.8安装jdk yum install java-11-openjdk当服务器中有多个版本jdk&#xff0c;切换指定jdk版本 alternatives --config java按照提示输入编号即可切换&…

古诗词学习鉴赏APP设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

【Java基础】抽象类和接口的使用

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、抽象类抽象类概念…

头条号热点采集工具-头条号热文采集软件

有一种魔法&#xff0c;能让信息传遍大地&#xff0c;让新闻在互联网上迅速传播&#xff0c;引发关注和讨论&#xff0c;那就是头条热点。无论你是一名自媒体创作者&#xff0c;还是一个信息追踪者&#xff0c;头条热点都是你不能忽视的宝贵资源。然而&#xff0c;如何获取这些…

Linux关于gittee的远端仓库的连接和git三板斧

目录 1.网页操作 2.Linux操作 查看Linux系统中是否安装git指令 安装git指令 链接远端仓库 设置 .gitignore文件 3.git三板斧 1.网页操作 首先我们要在gittee建立一个仓库 这是我自己的勾选方案&#xff0c;大家可以参考一下。 这个方案勾选最下面的三个选项才有&#x…