数据结构和算法学习记录——设计循环队列(数组实现循环队列)核心思路、题解过程、完整题解

目录

题目描述 

题目示例 

核心思路 

链表实现

数组实现

重点

题解过程

结构体类型定义

创建一个循环队列并初始化

判断循环队列为空或为满

入队列函数

出队列函数

取队头数据

取队尾数据

销毁循环队列

完整题解

题目来源:力扣

题目描述 

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

题目示例 

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

核心思路 

循环队列可以用链表实现,也可以用数组实现。

链表实现

数组实现

重点

无论使用数组实现还是链表实现,循环队列都是需要多开一个空间。也就是说,当我们需要存n个数据,那使用循环队列的话,就要开n+1个空间,否则无法判断队列为空以及队列为满。

head指向头,tail指向尾,n表示循环队列能存储多少个数据。

数组循环列队

判空条件:head == tail

判满条件:head == (tail+1) %(n+ 1)

 

(例如:一个循环队列能存储3个数据,那么它循环队列满的情况下,tail指向的位置就是第五个,下标为3; (3(tail) + 1) % (3(n) + 1)) = 0 == head)

链表循环队列

判空条件:head == tail

判满条件:head == tail-> next

题解过程

数组实现

结构体类型定义

因为循环队列的大小题目要求中是在创建队列函数中进行malloc的,所以我们设计结构体时,就创建指针变量,用于后面存储函数中malloc的地址;创建两个下标,分别指向头和尾;创建一个变量记录循环队列的存储容量。

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

创建一个循环队列并初始化

先开辟一个循环队列结构体大小的空间,再开辟循环队列结构体内部数组大小的空间;并进行初始化。

MyCircularQueue* myCircularQueueCreate(int k)
{
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    cq->a = (int*)malloc(sizeof(int) * (k + 1));
    cq->head = cq->tail = 0;
    cq->k = k;

    return cq;
}

判断循环队列为空或为满

根据前面判空判满的条件直接写即可

bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
    return obj->head == obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
    return (obj->tail+1) % (obj->k+1) == obj->head;
}

入队列函数

判断队列是否为满,为满的话直接返回false;不为满则插入数据后,++tail,同时++tail时会有两种情况:

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
    if(myCircularQueueIsFull(obj))
        return false;
    obj->a[obj->tail] = value;
    (obj->tail)++;
    obj->tail %= (obj->k+1);

    return true;
}

出队列函数

思路与入队列是一致的,只不过移动的从tail变成head,换成用head来操作即可。

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
        return false;
    (obj->head)++;
    obj->head %= (obj->k+1);
    return true;
}

取队头数据

取队头很简单,head指向的就是队头的数据。注意题目要求:循环队列为空的话就返回-1。

int myCircularQueueFront(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[obj->head];
}

 

取队尾数据

取队尾会有两种情况:

情况二可以有两种解决方法:

  1. 判断 当tail == 0时,取数组下标为n的数据
  2. 作统一计算处理,建立一个下标变量i,i = (tail + n)%(n+1)。取下标为i的数据即为队尾数据。 例:取情况一的队尾-> i = (3 + 3) % (3 + 1) = 2,下标为2的数据正是队尾数据[3]; 再取情况二的队尾-> i = (0 + 3) % (3 + 1) = 3,下标为3的数据正是队尾数据[4]。 
//第一种
// int myCircularQueueRear(MyCircularQueue* obj)
// {
//     if(myCircularQueueIsEmpty(obj))
//         return -1;

//     if(obj->tail == 0)
//         return obj->a[obj->l];
//     else
//         return obj->a[obj->tail-1];
// }
//第二种
int myCircularQueueRear(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
    {
        int i = ((obj->tail)+(obj->k)) % ((obj->k)+1);
        return obj->a[i];
    }
  
}

 

销毁循环队列

注意是有两层的空间需要free,由内到外free即可。

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

完整题解

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


MyCircularQueue* myCircularQueueCreate(int k)
{
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    cq->a = (int*)malloc(sizeof(int) * (k + 1));
    cq->head = cq->tail = 0;
    cq->k = k;

    return cq;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
    return obj->head == obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj)
{
    return (obj->tail+1) % (obj->k+1) == obj->head;
}


bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
    if(myCircularQueueIsFull(obj))
        return false;
    obj->a[obj->tail] = value;
    (obj->tail)++;
    obj->tail %= (obj->k+1);

    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
        return false;
    (obj->head)++;
    obj->head %= (obj->k+1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[obj->head];
}

//第一种
// int myCircularQueueRear(MyCircularQueue* obj)
// {
//     if(myCircularQueueIsEmpty(obj))
//         return -1;

//     if(obj->tail == 0)
//         return obj->a[obj->l];
//     else
//         return obj->a[obj->tail-1];
// }
//第二种
int myCircularQueueRear(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
    {
        int i = ((obj->tail)+(obj->k)) % ((obj->k)+1);
        return obj->a[i];
    }
  
}


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

/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

end


学习自:比特徐靖杭——数据结构与算法课程

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Sentinel滑动时间窗限流算法原理及源码解析(下)

文章目录对统计数据如何使用获取之前统计好的数据对统计数据如何使用 流控快速失败 获取之前统计好的数据

SpringBoot 项目的创建与启动

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

iosApplePay

1、Apple Pay 接入工程 - 简书 // 设置币种、国家码及merchant标识符等基本信息 PKPaymentRequest *payRequest [[PKPaymentRequest alloc]init]; payRequest.countryCode "CN"; //国家代码 payRequest.currencyCode "CNY"; //RMB的币种代码 …

“被裁员之前,没得到任何风声,措手不及...” 一个在职6年测试工程师内心独白

前言 一个码农(软件测试工程师)的自白 小张: 我们用工作五年的积蓄,在这个一线城市买了房子,买了车子,然后领证。我也在6年前进入了一个很多人梦寐以求新的公司 码农的新生活开始了。在这家公司里&…

ChatGPT如何为企业提供帮助?

数字化转型是指利用技术来改变企业的运营方式并为客户提供价值,这不仅仅是关于如何采用新的技术或工具。要想取得成功,就需要从根本上改变文化和心态。 ChatGPT如何为企业提供帮助?从数据分析到知识管理再到客户服务等等,人工智能聊天机器人…

光伏发电系统模拟及其发电预测开源python工具pvlib

1. 太阳辐照量模拟 pysolar是一个用于计算太阳位置和辐照量的Python库。它是基于python语言编写的,可以方便地在各种python项目中使用。pysolar主要用于计算太阳的位置、太阳高度角、太阳方位角、日出和日落时间等信息。这些信息可以用于太阳能电池板和太阳能集热器…

【设计模式】创建型-抽象工厂模式

文章目录一、抽象工厂模式1.1、产品族、产品等级1.2、抽象工厂模式中的角色1.3、实例一、抽象工厂模式 在工厂方法模式中,每一个具体的工厂子类只能生成一种具体的产品,如果想要生产另外一种产品,就需要重新定义一个抽象工厂类,这…

泡泡玛特“失速”,盲盒经济迎来拐点?

配图来自Canva可画​ 前些年泡泡玛特的飞速增长,曾经在行业内外引起了广泛的反响,其主打的盲盒经济也曾风靡一时、被众多行业效仿。不过,这种情况在疫情肆虐的2022年似乎受到了一些影响,这在其财报中就有所体现。 3月29日&#…

Python 小型项目大全 61~65

六十一、ROT13 密码 原文:http://inventwithpython.com/bigbookpython/project61.html ROT13 密码是最简单的加密算法之一,代表“旋转 13 个空格”密码将字母A到Z表示为数字 0 到 25,加密后的字母距离明文字母 13 个空格: A变成N&…

【Android】之【自定义View实践】

这里以一个进度条的加载为例子&#xff0c;先看效果&#xff08;运行效果是动态变化的&#xff09; 一、自定义属性 首先在res->values目录下新建attrs资源文件&#xff0c;如下图&#xff1a; 内容如下&#xff1a; <?xml version"1.0" encoding"utf…

SpringBoot基础学习之(九)添加员工的信息

本次项目所有能够使用的静态资源可以免费进行下载 静态资源 在本篇代码DAO层将通过Java文件去实现&#xff0c;在这里就不连接数据&#xff0c;然后通过jdbc将数据库内容的内容显示出来 案例&#xff1a;员工管理系统 上一篇博文的主要的内容是展示员工的信息&#xff0c;本篇…

Oracle JDK 和 OpenJDK 有什么区别?

可能在看这个问题之前很多人和我一样并没有接触和使用过 OpenJDK 。那么 Oracle JDK 和 OpenJDK 之间是否存在重大差异&#xff1f;下面我通过收集到的一些资料&#xff0c;为你解答这个被很多人忽视的问题。 首先&#xff0c;2006 年 SUN 公司将 Java 开源&#xff0c;也就有…

JAVA——网络编程基本概念

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

腾讯云轻量服务器和云服务器区别对比(超详细)

腾讯云轻量服务器和云服务器有什么区别&#xff1f;为什么轻量应用服务器费用更低&#xff1f;是因为轻量服务器CPU内存性能比云服务器CVM性能差吗&#xff1f;轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程序或开发测试环境&#xff0c;云服务器CV…

orcad library builder 建库及报错问题

目录 一.安装orcad library builder 二.orcad library builder 使用 1.建立一个orcad 原理图库测试下 尝试理解tcl那段的意思 xml文件导入建orcad库 折腾了2个多小时&#xff0c;居然没有直接方案搞定&#xff0c;简单记录下&#xff0c;后面遇到该问题的兄弟可参考借鉴&am…

Java集合框架之collection

1. 什么是集合 1.1 概念 对象的容器&#xff0c;实现类对对象常用的操作。 1.2 和数组的区别 数组长度固定&#xff0c;集合长度不固定。数组可以存储基本类型和引用类型&#xff0c;集合只能存储引用类型。 1.3 位置 java.util.*; 2. Collection体系 2.1 Collection父接…

网络编程 1

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启javaEE的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 网络编程 什么是网络编程&#xff1f;…

ASP网上视频点播系统的设计与实现

在线视频服务系统的功能模块划分如下图&#xff08;2-2&#xff09;所示&#xff1a; 电影分类浏览 用户可以通过电影的类别进行浏览。显示近期热门电影&#xff0c;近期点机排行。用户能很方便的找到自己感兴趣的电影进行观看。 电影搜索 如果用户有很明确的目的&#xff0c;…

JUC结构

JUC是java.util.concurrent包的简称在Java5.0添加&#xff0c;目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题&#xff01;进程与线程的区别&#xff1a;进程 : 一个运行中的程序的集合; 一个进程往往可以包含多个线程,至少包含一个线程…

JVM的内存区域划分

目录 1、程序计数器&#xff08;内存中最小的一块&#xff0c;里面保存了当前线程下一条执行的指令的地址&#xff09; 2、栈&#xff08;保存局部变量和方法调用的信息&#xff09; 3、堆 &#xff08;成员变量和new出来的对象都在堆上&#xff09; 4、方法区&#xff08…