【LeetCode】环形队列实现

news2024/12/22 23:50:30

目录

  • 前言
  • 1. 环形队列概念
  • 2. 循环队列实现设计
  • 3. 功能实现
    • 3.1 定义
    • 3.2 初始化
    • 3.3 判断队列是否为空
    • 3.4 判断队列是否为满
    • 3.5 入栈
    • 3.6 出栈
    • 3.7 获取队头数据
    • 3.8 获取队尾数据
    • 3.9 销毁
  • 4. 总结
  • 5. 完整通过代码


前言

之前我们学习环形链表相关问题,现在我们来看看环形队列有什么不同呢


循环队列题目链接

1. 环形队列概念

循环队列是一种线性数据结构,其操作依然是先进先出原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
最大的特点就是可以用利用这个队列之前用过的空间。
在这里插入图片描述


2. 循环队列实现设计

循环链表可以使用数组或链表实现
我这里用数组实现
如果需要存放是k个数据,我们就需要开辟k+1个数据空间,不然就无法判定空和满,导致数据插入和删除异常
需要两个变量来标识头(head)和尾(tail),出队front就向前移动,入队rear向前移动,但是这样会造成一个问题数组越界,循环就很好解决了这个问题,越界了就回到第一个数据位置。

  • 判空:head == tail
  • 盘满:head+1 == tail

3. 功能实现

3.1 定义

我们使用数组实现,需要一个数组,还有2个标志头(head)和尾(tail)的变量,和一个标志存放多少数据的变量k

typedef struct {
    int* a;
    int head;
    int tail;
    int k;
} MyCircularQueue;

3.2 初始化

首先我们需要创建队列结构体,在给里面成员赋值,之前说了我们需要k+1数据的空间,防止不知道满了和空的情况,head和tail刚开始都是0,k还是实参传过来的,我们需要的是k+1数据的空间
在这里插入图片描述

MyCircularQueue* myCircularQueueCreate(int k) {
    // 创建队列结构体
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    
    // 为队列里的数组创建k+1空间
    cq->a = (int*)malloc((k+1) * sizeof(int));
    cq->head = cq->tail = 0;
    cq->k = k;
    
    return cq;
}

3.3 判断队列是否为空

head和tail相等,就是空,不是就有数据

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    // head和tail相等就是空
    return obj->head == obj->tail;
}

3.4 判断队列是否为满

因为多开了一个数据空间,所以可以判断队列是否为满,tail+1 == head,就满了,多开一个数据的空间,可以保证满了的时候,tail和head无论什么情况,都至少有一个空间的距离,但是tail可能会越界,我需要取余
a只要取余b, a % b,余数一定是 0——b - 1,所以tail取余就不会越界,正好也满足了越界回到第一个数据位置。
而且还需要注意优先级问题,tail和k都是先加1,在进行取余
(obj->tail+1) % (obj->k+1) == obj->head

在这里插入图片描述

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    // tail+1取余k+1,等于head,就是满
    return (obj->tail+1) % (obj->k+1) == obj->head; 
}

3.5 入栈

  1. 满了的就不能入数据了
  2. 插入数据tail就会增加,可能会越界,同样需要取余

在这里插入图片描述

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    // 队列满了,就不能插入数据
    if (myCircularQueueIsFull(obj))
        return false;

    obj->a[obj->tail] = value;
    obj->tail++;
    
    // 插入数据会导致tail下标越界,越界处理:越界了就回到开始位置
    obj->tail %= obj->k+1;
    return true;
}

3.6 出栈

  1. 队列为空不能出数据
  2. 出栈,head就会向前移动,同样也会有越界问题,也需要取余
    在这里插入图片描述
ool myCircularQueueDeQueue(MyCircularQueue* obj) {
    // 队列为空,不能删除数据
    if (myCircularQueueIsEmpty(obj))
        return false;

    obj->head++;
    // 删除数据会导致head下标越界,越界处理:越界了就回到开始位置
    obj->head %= obj->k+1;
    return true;
}

3.7 获取队头数据

队列为空不能取数据,返回数据的head位置的数据即可

int myCircularQueueFront(MyCircularQueue* obj) {
     // 队列为空,不能取数据
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 返回头下标的数据
    return obj->a[obj->head];
}

3.8 获取队尾数据

队列为空不能取数据,由于是先插入数据,后++,我们要取tail数据,需要-1,这个有两个情况,需要特殊处理

  • tail不为0,直接取数组tail - 1位置即可
  • tail为0,我们减1,tail为-1就会越界,返回最后一个数据的下标就是k的位置,这里有两种解决方法1、if判断 2、取余
  1. if判断
int myCircularQueueRear(MyCircularQueue* obj) {
    // 队列为空,不能取数据
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // tail等于0会越界,取消返回最后一个数据的下标
    if (obj->tail == 0)
        return obj->a[obj->k];

    return obj->a[obj->tail - 1];
}
  1. 取余
    由于空间长短是k+1,下标是k,他们之间最少也会差1,所以当前位置tail+k,在取余k+1,刚好就返回了tail的位置的前一个数据位置
    tail+k = k+1
    tail - 1

int myCircularQueueRear(MyCircularQueue* obj) {
    // 队列为空,不能取数据
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 由于空间长短是k+1,下标是k,他们之间最少也会差1
    // 所以当前位置tail+k,在取余k+1,刚好就返回了tail前一个数据位置
    // tail+k = k+1
    // tail - 1
    int tail = (obj->tail+obj->k) % (obj->k+1);
    return obj->a[tail];
}

3.9 销毁

同样也有两层结构,我们需要前销毁里层,在销毁外层
在这里插入图片描述

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

4. 总结

循环队列用数组实现就需要多注意数组越界问题


5. 完整通过代码

typedef struct {
    int* a;
    int head;	// 头
    int tail;	// 尾
    int k;		// 队列长度
} MyCircularQueue;

// 由于要先调用这两个函数,所以先声明
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);

MyCircularQueue* myCircularQueueCreate(int k) {
    // 创建队列结构体
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    
    // 为队列里的数组创建k+1空间
    cq->a = (int*)malloc((k+1) * sizeof(int));
    cq->head = cq->tail = 0;
    cq->k = k;
    
    return cq;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    // 队列满了,就不能插入数据
    if (myCircularQueueIsFull(obj))
        return false;

    obj->a[obj->tail] = value;
    obj->tail++;
    
    // 插入数据会导致tail下标越界,越界处理:越界了就回到开始位置
    obj->tail %= obj->k+1;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    // 队列为空,不能删除数据
    if (myCircularQueueIsEmpty(obj))
        return false;

    obj->head++;
    // 删除数据会导致head下标越界,越界处理:越界了就回到开始位置
    obj->head %= obj->k+1;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
     // 队列为空,不能取数据
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 返回头下标的数据
    return obj->a[obj->head];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    // 队列为空,不能取数据
    if (myCircularQueueIsEmpty(obj))
        return -1;

    // 由于空间长短是k+1,下标是k,他们之间最少也会差1
    // 所以当前位置tail+k,在取余k+1,真好就返回了前一个数据位置
    // tail+k = k+1
    // tail - 1

    // 取余法
    //int tail = (obj->tail+obj->k) % (obj->k+1);
    //return obj->a[tail];

     if (obj->tail == 0)
        return obj->a[obj->k];

    return obj->a[obj->tail - 1];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    // head和tail相等就是空
    return obj->head == obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    // tail+1取余k+1,等于head,就是满
    return (obj->tail+1) % (obj->k+1) == obj->head; 
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    obj->head = obj->tail = obj->k = 0;
    free(obj);
}

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

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

相关文章

opencv_21_直方图均衡化

1)void histogram_eq_demo(Mat& image); 2)void ColorInvert::histogram_eq_demo(Mat& image) { Mat gray; cvtColor(image, gray, COLOR_BGR2GRAY); imshow("灰度图像", gray); Mat dst; equalizeHist(gray, ds…

B2985A是德科技B2985A高阻计

181/2461/8938产品概述: B2985A 静电计/高阻表 描述 B2985A 静电计/高阻表是全球少有具有图形显示功能的静电计,可凭借 0.01 fA(0.01 x 10-15 A)的分辨率帮助您可靠测量弱电流,并可测量高达 10 PΩ(10 x 1…

基于FPGA的去雾算法

去雾算法的原理是基于图像去模糊的原理,通过对图像中的散射光进行估计和去除来消除图像中的雾霾效果。 去雾算法通常分为以下几个步骤: 1. 导引滤波:首先使用导引滤波器对图像进行滤波,目的是估计图像中散射光的强度。导引滤波器…

C++ | Leetcode C++题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; class Solution { public:void setZeroes(vector<vector<int>>& matrix) {int m matrix.size();int n matrix[0].size();int flag_col0 false;for (int i 0; i < m; i) {if (!matrix[i][0]) {flag_col0 true;}for …

C语言 | Leetcode C语言题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; void setZeroes(int** matrix, int matrixSize, int* matrixColSize) {int m matrixSize;int n matrixColSize[0];int flag_col0 false;for (int i 0; i < m; i) {if (!matrix[i][0]) {flag_col0 true;}for (int j 1; j < n; j…

透明屏幕的亮度如何?在强光环境下是否仍然清晰可见?

透明屏幕的亮度是一个重要的指标&#xff0c;决定了屏幕在明亮环境中的可视程度。在透明屏幕领域&#xff0c;高亮度的屏幕可以确保在强光环境下仍然能够清晰显示内容。 OLED透明屏通常具有较高的亮度&#xff0c;可以达到500尼特以上&#xff0c;这使得它们在明亮的环境中仍然…

SaToken框架实现在Rpc上下文的login处理逻辑

最近在工作中遇到一个需求&#xff0c;需要在项目A中实现一个rpc接口供其他项目调用&#xff0c;接口返回登录token&#xff0c;从而实现其他项目的用户能免密登录到项目A。 项目A是用了SaToken来做的鉴权&#xff0c;原本我的打算是直接在rpc中调用StpUtil.login()方法来实现登…

【论文阅读】 Loss Functions for Image Restoration with Neural Networks

Loss Functions for Image Restoration with Neural Networks 论文地址摘要I. 引言II 相关工作用于图像恢复的神经网络B 找到更好的解决方案。 三、图像恢复的损失层A. l1 错误 The l1 ErrorB. SSIMC. MS-SSIMD. The Best of Both Worlds: MS-SSIM L1 四、结果A. Joint Denois…

零基础编程学python:如何从零开始学习并使用Python编程语言

零基础编程学python&#xff1a;如何从零开始学习并使用Python编程语言 Python是一种非常流行的编程语言&#xff0c;由于其简单的语法和强大的功能&#xff0c;使其成为初学者和专业开发者的首选。无论您是数据科学家、网络开发者还是自动化工程师&#xff0c;Python都能提供必…

多组间比较散点图+误差棒(自备)

目录 数据 计算四分位值 作图 数据 rm(list ls()) library(ggplot2) library(dplyr) library(ggpubr) library(reshape2) library(tidyverse)data <- iris##鸢尾花数据集 dat <- data[,c(5,1)]#单个数据进行分析 计算四分位值 #根据分组计算四分位及中位数 dat1 …

软件测试与管理:黑盒测试-等价类划分法和 边界值分析法

知识思维导图&#xff1a; 例题1&#xff1a;日期检查功能的等价类划分 设有一个档案管理系统&#xff0c;要求用户输入以年月表示的日期。假设日期限定在1990年1月~2049年12月&#xff0c;并规定日期由6位数字字符组成&#xff0c;前4位表示年&#xff0c;后2位表示月。现用等…

RAG进阶(二): RAG 融合(rag fusion)

在上一篇博客中&#xff0c;我们学习了多重查询(Multi Query)技术&#xff0c;Multi Query的基本思想是当用户输入查询语句(自然语言)时&#xff0c;我们让大模型(LLM)基于用户的问题再生成多个查询语句&#xff0c;这些生成的查询语句是对用户查询语句的补充&#xff0c;它们是…

okcc最新版本会被盗打吗?

OKCC是一款智能外呼系统&#xff0c;它提供了多种安全措施来防止系统被盗打。以下是一些关键的安全配置和管理措施&#xff1a; 立即挂失SIM卡&#xff1a;一旦发现OKCC系统被盗打&#xff0c;应立即联系运营商进行SIM卡的挂失&#xff0c;以阻止盗打者继续使用您的号码进行通信…

Mybatis进阶3--注解开发

先看&#xff1a; Mybatis进阶1-CSDN博客 Mybatis进阶2-CSDN博客 mybatis注解开发 前置&#xff1a;不需要xxxMapper..xml文件&#xff08;映射文件&#xff09; 在核心配置文件中&#xff1a;<mappers>标签只能使用&#xff1a;<package name"扫描的包&quo…

visio studio 中.NET Core(.net8.0)框架和.net framewok 框架有什么区别?

更新vs到2022版本后&#xff0c;新建项目时就多出不少选项&#xff0c;这里来个大家分享下.NET Core&#xff08;.net8.0&#xff09;框架和.net framewok的区别 如下图&#xff0c;不带后缀的就是使用.NET Core框架&#xff0c;后续选项是.net8.0。 .net framewok框架选项&am…

PDF高效编辑:一键批量,PDF转图片的快速解决方案

在数字化时代&#xff0c;PDF文件已成为工作和学习中不可或缺的一部分。然而&#xff0c;有时我们可能需要将PDF转换为图片&#xff0c;以便更轻松地编辑、共享或处理。为了满足这一需求&#xff0c;许多高效的PDF编辑工具应运而生&#xff0c;其中“办公提效工具”一键批量PDF…

ESP8266做主机 手机网络助手为从机

ATCIFSR查看地址&#xff0c;一般ESP8266 为192.168.4.1 在手机上下载网络调试助手&#xff0c;打开TCP客户端 创建后192.168.4.1 端口8089然后连接ESP8266热点。 ESP向手机发数据前先发送要发几个数据ATCIPSEND0,8表示发8个&#xff0c;然后再发8个数 上面创建好热点后&…

MFC实现点击列表头进行排序

MFC实现点击列表头排序 1、添加消息处理函数 在列表窗口右键&#xff0c;类向导。选择 IDC_LIST1&#xff08;我的列表控件的ID&#xff09;&#xff0c;消息选择LVN_COLUMNCLICK。 2、消息映射如下 然后会在 cpp 文件中生成以下函数 void CFLashSearchDlg::OnLvnColumnclic…

权益商城系统源码,支持多种支付方式

权益商城系统源码&#xff0c;支持多种支付方式&#xff0c;后台商品管理&#xff0c;订单管理&#xff0c;串货管理&#xff0c;分站管理&#xff0c; 会员列表&#xff0c;分销日志&#xff0c;应用配置。 上传到服务器&#xff0c;修改数据库信息&#xff0c;导入数据库&a…

rust调用SQLite实例

rusqlite库介绍 Rusqlite是一个用Rust编写的SQLite库&#xff0c;它提供了对SQLite数据库的操作功能。Rusqlite的设计目标是提供一个简洁易用的API&#xff0c;以便于Rust程序员能够方便地访问和操作SQLite数据库。 Rusqlite的主要特点包括&#xff1a; 遵循Rust的类型系统和…