数据结构每日亿题(七)

news2024/11/20 14:44:08

文章目录

    • 一题目
    • 二.思路
    • 2.1链表
    • 2.2数组
    • 三.代码

一题目

原题传送门:力扣
题目:
在这里插入图片描述
题目的意思是让你写一个数据结构,这个结构的特点和队列一样先进先出,然后完成:判断是否为空,判断是否为满,添加一个元素,删除一个元素,获取队尾元素,获取队首元素这些函数。
他和普通队列的区别是,这个循环队列它的空间大小是确定的,你给的值是k,这个队列就会给你开辟好k个元素大小的空间,满了就不能继续添加了。而队列是空间不够了可以继续开辟。

这个循环队列在满了之后,只有删除掉一个元素才能继续添加新的元素。

二.思路

2.1链表

接触过队列的应该都知道,队列是先进先出,用链表来实现比较容易,那我们这个循环队列可不可以用链表来实现呢?现在先分析一下链表实现可不可以,如果可以的话,再看容不容易实现。首先可以判断的是要实现一个循环队列,我们可以用循环链表实现:
在这里插入图片描述
假设开辟了四个元素的空间,也就是这个队列最大能放四个元素。然后定义两个指针方便我们找到头和尾,每添加一个元素rear往后走一步,front不变。每删除一个元素front向后走一步,rear不变。这里可以看到判断是否为空这个函数很好写:看看两个指针指向的位置是否相等就行。但是判满呢?rear一直向后走走到最后的时候又回来了。
在这里插入图片描述现在我们发现front和rear相等的时候可以判断是满,这样子就和判空的函数判断条件冲突了。所以在这里我们有改进了一下。多开辟一块空间:
在这里插入图片描述
此时还是只能放4个元素,多出来的那一块只是为了方便判断这样判满的条件就是rear->next是否和front相等。

现在可以看到判空判满是挺好写的,再仔细观察,尾插就是需要加入的元素放在rear指向的节点里,首删就是让front向后走一步就行。这样的话尾插首删这两个函数也很容易写出来。

再来看最后两个函数获取队列首元素和尾元素,首元素是把front指向的元素返回出来,这里最麻烦的是获取尾元素,要获取尾元素,首先肯定要知道rear上一个节点的位置,但是我们这是单链表,上一个节点的地址需要在定义一个指针每次都指向rear指向这个节点的上一个节点,这样也能做出来,但是感觉不是那么方便。当然用双向循环链表也能实现,这样的话在开始开辟空间的时候也会比较麻烦。所以现在我想用另一种结构来实现这个循环队列:数组。

2.2数组

根据刚才对链表的分析,这个数组也需要多开辟一块空间,这里我们定义两个变量,front和rear,注意这里我们就不定义指针了,这两个变量表示的是相应的数组下标,用两个变量来表示的优势是它们是一个整数可以做一些指针做不了的运算。这里front,rear变化的方式和链表一样,每删一个元素front向后走一步,每添加一个元素rear向后走一步。
在这里插入图片描述这里假设开辟了5个元素大小的空间。判空很容易,看front和rear是否相等就行。
那判满呢?
在这里插入图片描述是rear==5的时候就是满吗?如果此时删除两个元素:

在这里插入图片描述现在我们再添加两个元素,这时候我们希望rear指向的地方是这里:
在这里插入图片描述这种情况rear的下一个位置如果和front相等就说明这个队列是满的。
所以队列满的情况有两种:
在这里插入图片描述虽然有两种情况但可以用一个式子来说明清楚:

判断(rear + 1) % (k + 1)的值和front是否相等
//这里的k就是队列最多的元素个数

这里的k我们设置的是5,看第一种情况,此时rear等于1,带进去这个式子结果是2%6 = 2,而2就是front的值,因为二者相等,所以可以说这个队列是满的。
再看第二种情况,6%6的结果是0,而且此时front也等于0,二者相等所以可以说这个队列是满的。

这样一分析这样写确实可以判断队列是不是满的。

现在开始想插入,删除的函数能不能写。
先看尾插:
在这里插入图片描述这要在下标为rear的地方插入一个元素就行,看上去很容易,但是如果此时删除两个元素:
在这里插入图片描述在添加一个元素:
在这里插入图片描述如果再添加一个元素之前,我们希望rear代表的下标应该是这里:
在这里插入图片描述也就是说rear在等于5的时候,然后在添加一个函数之前rear不等于6而是0,换句话说在添加一个元素后首先rear要往后走一步,而且做一步之后它所在的范围是0-5.所以我们可以这样写:

obj->a[obj->rear++] = value;
obj->rear %= (obj->k + 1);

同样在删除元素是front移动的规律和rear是一样的。

现在在考虑获取队首和队尾位置,获取队首的位置是最容易的,直接返回front所在下标的元素。
获取队尾稍微麻烦一点,因为我们要找的rear上一个的位置,其实麻烦也没麻烦多少,这里就需要多考虑一个特殊情况:
在这里插入图片描述当rear的值为0时上一个位置是-1,直接写的话会导致越界访问,而现在我们希望拿到的是a[k]也就是最后一个元素的位置。rear的取值范围是0-5,而我们希望得到的结果是1-5:
在这里插入图片描述当rear为1-5的时候可以不用考虑,通过上面这图,就可以总结出一个规律:

(obj->rear + obj->k) % (obj->k + 1)

这样就把rear和需要的结果联系起来了,因为取模的是k+1,这样把结果规定在0-5这个范围内,而rear=0时需要的结果是5,所以在%前面加上一个k.

这样我们基本就把题目所需的函数都写出来了。最后释放函数把定义的几个指针free掉就行

三.代码

//定义一个指针a用来接收开辟的数组空间的地址
//front,rear代表数组下标,一个指向数组头,一个指向尾
typedef struct {
    int* a;
    int front;
    int rear;
    int k;
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a = (int*)malloc(sizeof(int) * (k + 1));
    obj->front = obj->rear = 0;
    obj->k = k;

    return obj;
}

//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    //只有两个指针相等的时候才算空
    return obj->rear == obj->front;
}

//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    assert(obj);
    //rear的下一个和front相等
    //rear指向最后一个时是特例,此时rear的下一个应该等于0才算满
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
}

//尾插
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    assert(obj);

    //判满,空间是满的话不允许添加
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    //先将value的值放到此时数组下标是rear的地方,然后rear向后走一步
    obj->a[obj->rear++] = value;
    //rear的范围只能是0-5
    obj->rear %= (obj->k + 1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    assert(obj);

    //判空
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    obj->front %= (obj->k + 1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    assert(obj);

    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }

    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    assert(obj);

    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }

    return obj->a[(obj->rear + obj->k) % (obj->k + 1)];
}

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

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

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

相关文章

实验29:循迹传感器实验

今天讲一个基本实验 循迹实验 循迹传感器的原理是: CTRT5000传感器的红外发射管不断发射红外光。由于黑色吸收光线,当红外发射管照射黑色表面时,反射光较少,接收管接收的红外线较少。这表明黑色吸收光线的强度大,那么比较器输出高电平,指示灯熄灭。同样,当它在白色表面…

MCE虚拟筛选化合物库

Discovery Diversity Sets 新颖的化合物库! 药物筛选是发现药物先导物的重要途径,好的化合物库则是药物筛选的必备武器。MCE 拥有丰富的数据库资源,助力您的药物筛选研究!药物筛选研究与化合物新颖性密切相关。Discovery Divers…

单目标应用:求解旅行商问题(TSP)的猎豹优化算法(The Cheetah Optimizer,CO)提供MATLAB代码

一、猎豹优化算法 猎豹优化算法(The Cheetah Optimizer,CO)由MohammadAminAkbari等人于2022年提出,该算法性能高效,思路新颖。 参考文献: Akbari, M.A., Zare, M., Azizipanah-abarghooee, R. et al. The…

Linux实战案例——使用LNMP+WordPress搭建个人博客网站

一、案例目标 了解 LNMP 环境的组成。 了解 LNMP 环境的部署与安装。 了解 WordPress 应用的部署与使用二、环境介绍 1.LNMP LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写。L指Linux,N指Nginx,M一般指MySQL,也…

技术分享 | TiUP工具 - TiDB集群滚动升级核心流程解析

作者:贲绍华 爱可生研发中心工程师,负责项目的需求与维护工作。其他身份:柯基铲屎官。 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 引言&#xff1a…

运维工程师怎么找兼职?什么样的兼职合适?

运维老哥们应该都知道,这个岗位其实是个很宽泛的定义,不同公司对运维的要求也不一样。有些公司所谓运维就是桌面helpdesk ,有些公司就是网管。基本上从修电脑到会写点脚本做自动化,各个层次的都有。现状就是,有少数公司或者大厂的…

基于Django的图书交易系统

摘 要 随着信息化时代的到来,管理系统都趋向于智能化、系统化,图书交易系统也不例外,但目前国内的有些公司仍然都使用人工管理,图书销量越来越大,同时信息量也越来越庞大,人工管理显然已无法应对时代的变化…

第五课 算术运算

一、加法与减法 经过上次课的学习,我们已经学会了该如何在控制台中输出我们想要的内容了,但是计算机计算机,最早其实是用来进行计算的,Python能做这事吗,我们来试试。 看到这结果,估计很多同学就该说了&…

【每周研报复现】基于阻力支撑相对强度(RSRS)的市场择时

原创文章第106篇,专注“个人成长与财富自由、世界运作的逻辑, AI量化投资”。 今天要复现的研报是:”光大证券_金融工程深度:基于阻力支撑相对强度(RSRS)的市场择时——技术择时系列报告之一“。 研报核心…

写个注解帮你净化使用分布式锁的重复操作

RedissonAop实现分布式锁 前言 简介 Aop的意义 AOP 旨在从业务逻辑中分离出来通用逻辑,切面实现了跨越多种类型和对象的关注点(例如事务管理、日志记录、权限控制)的模块化。 例子 就以这段代码为例子,这段代码总是回去获取锁之…

【HTML】关于height值设置和显示不同的原因以及font-size对象为中文和英文的区别

关于height值设置和显示不同的原因 height: 100px; CSS中把高度设置为100px,但是实际测量发现高度为125px 这个是因为:笔记本默认显示大小为125%,所以100的125%就是125. 还有一点,在你写网页时,要注意网页的缩放一定…

050_阵列天线方向图乘积原理

天线增益概念。原创不易,恐有错误,恳请读者指正。碎片三分钟逛电巢App,收获一丢丢。 天线定向性(directivity) 假设理想的无定向性天线,在远场区的3D球面空间各方向的辐射功率都相等,则定义球面等辐射功率的方向图的定…

Linux内存泄露案例分析和内存管理分享

作者:李遵举 一、问题 近期我们运维同事接到线上LB(负载均衡)服务内存报警,运维同事反馈说LB集群有部分机器的内存使用率超过80%,有的甚至超过90%,而且内存使用率还再不停的增长。接到内存报警的消息&…

代码随想录day56|583. 两个字符串的删除操作|72. 编辑距离|编辑距离总结篇|Golang

代码随想录day56 考试周了解一下 目录 代码随想录day56 583. 两个字符串的删除操作 72. 编辑距离 动态规划之编辑距离总结篇 583. 两个字符串的删除操作 思路 动态规划一 本题和动态规划:115.不同的子序列相比,其实就是两个字符串都可以删除了&am…

2023职教高考报名开启,报考人数继续增加

进入11月起,各地区2023年职教高考报名已经陆续开始,报考考生主要以中职学校学生为主。根据南京日报的报道,11月1日就启动的江苏省职教高考报名,吸引了不少家长和学生的关注,有些专业的报名人数已经比2022年翻了不止一倍…

Flutter Hooks — 快速了解

Flutter Hooks — 快速了解 前言 Hooks,直译过来就是"钩子",是前端 React 框架加入的特性,用来分离状态逻辑和视图逻辑。现在这个特性并不只局限在于 React 框架中,其它前端框架也在借鉴。 我们都知道在 FLutter 开发中的一大痛点就…

图解 | 监控系统 Prometheus 的原理

本篇将会以图解的方式剖析 Prometheus 的原理。本文主要内容如下: 一、Prometheus 是什么? ELK Stack 日志收集和检索平台想必大家应该比较熟悉,Elasticsearch Filebeat Logstash Kibana。 ELK 架构 而 Prometheus 就相当于一整个 ELK&a…

功率放大器的主要指标有哪些呢

功率放大器是电子测量行业比较常见的能够放大信号源电压信号的仪器,虽然功率放大器的应用十分广泛,但是很多人对于功率放大器的主要指标参数还不了解,就让安泰电子来为大家介绍功率放大器的主要指标。 功率放大器的核心参数指标包括带宽、电压…

python多线程返回值问题重写Thread类的run方法

python多线程使用 文章目录python多线程使用一、案例二、说明1、针对第一种是有返回值的 ,可以通过future.result() 去拿到每个线程返回值2、无返回值问题3、我们可以重写这个Thread类重写了__init__、run方法和join方法,主要是start()涉及的方法太多了而…

Redis篇(5)——持久化

持久化 RDB 1、save会阻塞所有命令。而bgsave则不能与其他持久化命令同时执行 2、自动rdb的发起:servercorn默认每100ms执行一次,根据redisserver里面记录的dirty(上次save后修改的次数)和lastsave(上次save的时间&a…