循环队列:一道使数据结构萌新知道什么是“愁滋味“的题目

news2024/11/18 2:48:51

这破题目肝了我一天半才搞明白,也正是因为这道题目,我才豁然明白了李煜所说的"剪不断,理还乱...别是一般滋味在心头"到底是什么"滋味".在完全搞明白之前,真的是放有放不下,理也理不清...

但是理解之后你会发现,嘛い---,也就那么个回事嘛O(∩_∩)O

目录

1.题目:来自力扣

2.为什么选择数组(顺序表)是实现这道题的最好的方案

3. 有如何判断环状顺序表何种情况下为空,以及何种情况下为满的问题

4.需要实现的操作

5.具体操作的代码实现

5.1创建一个顺序表

5.2判空与判满操作

 5.3队尾加入新元素操作

 5.4队头删除元素操作

5.5显示头操作

5.6重难点:显示尾操作

6.写这条题目时顺便把自己的思路写了一下整理成笔记,分享一下


1.题目:来自力扣

2.为什么选择数组(顺序表)是实现这道题的最好的方案

  1. 简单性和易实现性:循环队列的实现相对简单,主要涉及数组的索引计算和循环移位。而链表的实现需要处理节点的创建、删除和指针操作,相对复杂
  2. 时间复杂度:在大多数情况下,循环队列的入队、出队操作的时间复杂度为O(1),因为只需要计算索引和进行简单的赋值操作。而链表的入队、出队操作可能涉及到节点的创建、删除和指针调整,时间复杂度为O(1)或O(n)。

3. 有如何判断环状顺序表何种情况下为空,以及何种情况下为满的问题

若空:则rear和front⼀定是指向同⼀位置的

若满:因为是循环顺序表(数组)那么理论上rear和front也是 .指向同⼀位置,但是这样便会与判空混淆,是⽆法操作的

这种问题我们称沩「假溢出」

所以,解决此问题的最佳方案便是⽤多额外开辟⼀个空间来解决假溢出问题

为确保队满时rear+1可以指向front,所以每次向队列中添加⼀个元素后rear 要指向当前元素的下⼀个位置,于是便有了rear+=1,然后顺理成章便有了 reart1=front来进⾏判断的代码.

如上图,如果rear到达循环队列最后⼀个位置时, rear=7,rear+1=8,但front =0,这并不符合我们的预期,故⽽我们设了⼀个值K,⽤于表示此循环队列中点共有多少个元素(这其中 包括为了解决假溢出⽽额开辟的空间)

⽤(rare+1)%(k+1)来控制rare范围

ps: k是怎么来的?先⽤malloc开辟整数倍的数组每个元素⼤⼩的空间 此时为k,再realloc对其进⾏扩展⾄(k+1),多⼀个假溢出空间。

4.需要实现的操作

bool myCircularQueueIsFull(MyCircularQueue* obj);//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj);//判满
MyCircularQueue* myCircularQueueCreate(int k); //初始化
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value);//入队
bool myCircularQueueDeQueue(MyCircularQueue* obj);//删除
int myCircularQueueFront(MyCircularQueue* obj);//显示头
int myCircularQueueRear(MyCircularQueue* obj);//显示尾
void myCircularQueueFree(MyCircularQueue* obj);//释放

5.具体操作的代码实现

5.1创建一个顺序表

typedef struct
{
	int* a;
	int front;
	int rear;
	int k;
} MyCircularQueue;
//使用malloc函数开辟环状顺序表所需空间
//realloc开辟额外空间结局假溢出问题
MyCircularQueue* myCircularQueueCreate(int k) 
{
	MyCircularQueue* obj0 = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
	MyCircularQueue* obj = (MyCircularQueue*)realloc(obj0->a, (k + 1) * sizeof(MyCircularQueue));
	obj->front = 0;
	obj->rear = 0;
	obj->k = k;
	return obj;
}

5.2判空与判满操作

//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
	return obj->front == obj->rear;
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
	return (obj->rear + 1) % obj->k + 1 == obj->front;
}

 5.3队尾加入新元素操作

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

注:rear指向队尾元素的下⼀个位置

问题:循环数组最后⼀个空间是为了解决假栈溢出是不放元素的,如果数组 满了rare指向如图所示位置,再进⾏下⼀次放⼊元素的操作时它不就直接被 if(myCircularQueueIsFull(obj))驳回了 就不存在rare⽐k+1⼤的情况了 为啥 这⾥还要⽤obj->rear = (obj->rear) % obj->k + 1进⾏范围限制呢? 

回答:判断队列是否满和⽤取模限定范围这两个操作是⼆选⼀,但是为了 保证代码的健壮性,所以最好两个都写

 5.4队头删除元素操作

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
	if (myCircularQueueIsEmpty(obj))
	{
		return false;
	}
	free(obj->a[obj->front]);
	obj->front++;
	obj->front = (obj->front) % obj->k+1;//要考虑front在尾巴的情况
	return true;
}

注:如图:front在尾巴时,此时front为7,进⾏⼀次删除操作后,front会变成8,但是 这个循环队列没有下标为8的元素,不在范围内,我们预期的是此时front为0,所以 ⽤取模obj->front = (obj->front) % obj->k+1进⾏范围限制操作

5.5显示头操作

//显示头
int myCircularQueueFront(MyCircularQueue* obj)
{
	if (myCircularQueueIsEmpty(obj))
	{
		return -1;
	}
	else
	{
		return obj->a[obj->front];
	}
}

5.6重难点:显示尾操作

int myCircularQueueRear(MyCircularQueue* obj)
{
	if (myCircularQueueIsEmpty(obj))
	{
		return -1;
	}
	else
	{
		return obj->a[obj->rear - 1 + obj->k+1] % obj->k+1;
	}
}

解析:

因为rear是指向队尾下⼀个位置,所以只有rear-1才是队尾 rear!=0时rear-1是没有任何问题的

但是,如果rear=0时,rear-1=-1,不在这个范围内

所以这个问题要分为rear=0和rear!=0两种情况进⾏分类讨论

1.rear!=0时

直接是(rear-1)%(k+1),当A%B是,如果a[obj->rear - 1] % obj->k+1;

2.rear=0时

按循环链表的逻辑lai讲,rear-1=7,于是乎代数上,我们⽤rear-1+k-1=7, 但是如果rear不是0,⼜会发⽣超出范围的情况,我们可以%(k+1)

如此,将两种情况归纳⼀下,就是 return obj->a[obj->rear - 1 + obj- >k+1] % obj->k+1;

当然,如果嫌这么写太别扭,两种情况也可以⽤if...else语句拆开直⽩地 分情况写

6.写这条题目时顺便把自己的思路写了一下整理成笔记,分享一下

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

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

相关文章

瑞_Redis_短信登录(一)

文章目录 项目介绍1 项目准备1.1 导入SQL1.2 导入后端项目1.2 导入前端项目 🙊 前言:本文章为瑞_系列专栏之《Redis》的实战篇的短信登录章节的项目准备小节。由于博主是从B站黑马程序员的《Redis》学习其相关知识,所以本系列专栏主要是针对该…

Tonka Finance,BTCFi 浪潮的发动机

在 2023 年年初,Ordinals 技术方案为比特币 Layer1 带来了一种全新的资产发行方式,此后一场以比特币生态为主战场的新一轮资金、注意力价值争夺战打响,并且越来越多的加密原教旨主义者、密码极客们加入这场战争中。我们看到,铭文市…

【操作系统概念】 第1章:导论

文章目录 关于本书内容0.前言1.1操作系统的功能1.1.1 用户视角1.1.2 系统视角1.1.3 操作系统的定义 1.2 计算机系统的组成1.2.1 计算机系统的运行1.2.2 存储结构1.2.3 I/O结构 1.3 计算机系统体系结构1.4 操作系统的结构1.5 操作系统的执行1.5.1 双重模式与多重模式的执行1.5.2…

DolphinScheduler——介绍及架构设计

目录 一、DolphinScheduler介绍 1.1 概述 1.2 特性 1.2.1 简单易用 1.2.2 丰富的使用场景 1.2.3 High Reliability 1.2.4 High Scalability 1.3 名词解释 1.3.1 名词解释 1.3.2 模块介绍 二、DolphinScheduler架构原理 2.1 系统架构图 2.2 架构说明 2.2.1 Maste…

【AI视野·今日Sound 声学论文速览 第五十一期】Mon, 4 Mar 2024

AI视野今日CS.Sound 声学论文速览 Mon, 4 Mar 2024 Totally 6 papers 👉上期速览✈更多精彩请移步主页 Daily Sound Papers VoxGenesis: Unsupervised Discovery of Latent Speaker Manifold for Speech Synthesis Authors Weiwei Lin, Chenhang He, Man Wai Mak, …

66-ES6:var,let,const,函数的声明方式,函数参数,剩余函数,延展操作符,严格模式

1.JavaScript语言的执行流程 编译阶段:构建执行函数;执行阶段:代码依次执行 2.代码块:{ } 3.变量声明方式var 有声明提升,允许重复声明,声明函数级作用域 访问:声明后访问都是正常的&…

最新LangChain+GLM4开发AI应用程序系列(三):RAG检索增强生成篇

最新LangChainGLM4开发AI应用程序系列(三):RAG检索增强生成篇 一、前言二、RAG介绍1、文档加载器2、文本分割器3、嵌入模型4、向量数据库 三、RAG开发案例1、创建智谱GLM4大模型对象2、加载文档3、文本分割4、向量化存储5、向量库检索6、生成…

初始网络 --- 网络基础

目录 0、 前言 1、 计算机网络发展背景 1.1. 局域网(LAN) && 广域网(WAN) 2、 认识并理解协议 3、 初始网络协议 3.1. 协议分层 4、 TCP/IP 五层(或四层)模型 4.1. 简单了解TCP/IP层状体系 4.2. TCP/IP协议层状结构和计算机层状结构的关系 5、 OSI七层模型 …

程序员如何选择职业赛道:探索未知,寻找激情

作为程序员,我们时常面临职业选择的难题。在这个充满变革的行业中,如何选择适合自己的职业赛道成为了我们关注的焦点。本文将探讨程序员如何选择职业赛道,帮助你找到适合自己的发展方向。 一、认识自己的兴趣和激情 首先,我们需要…

为什么要用云手机进行国外社媒监控?

随着全球化的不断发展,社交媒体已成为企业推动全球品牌知名度和业务流量的关键渠道。在这个数字时代,云手机作为一种强大的工具,为国外社交媒体监控提供了全新的可能性。在这篇文章中,我们将探讨使用云手机进行国外社媒监控的重要…

RHCSA练习2

一、实验题目 1、文件查找 (1)在当前目录及子目录中,查找小写字母开头的txt文件 [rootroot ~]# cd /etc [rootroot etc]# find . -type f -name [a-z]*.txt (2)在/etc及其子目录中,查找host开头的文件 …

Java解决杨辉三角

Java解决杨辉三角 01 题目 给定一个非负整数 *numRows,*生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]示例 2: 输入: numRo…

人工智能-飞桨

文章目录 概要安装零基础教程基础知识小结 概要 集核心框架、基础模型库、端到端开发套件、丰富的工具组件于一体的深度学习平台 官方入口 安装 python安装 python官方下载 PaddlePaddle安装 python -m pip install paddlepaddle2.6.0 -i https://mirror.baidu.com/pypi/s…

【C++】类和对象终篇

个人主页 : zxctscl 文章封面来自:艺术家–贤海林 如有转载请先通知 文章目录 1. 前言2. 友元2.1 友元函数2.2 友元类 3. 内部类4. 匿名对象5. 拷贝对象时的一些编译器优化6. 再次理解类和对象 1. 前言 在上一篇博客中提到了类和对象中的构造函数与stat…

数据库系统概论(超详解!!!) 第二节 数据模型

1.数据模型分为两类(两个不同的层次) (1) 概念模型 ,也称信息模型,它是按用户的观点来对数据和信息建模,用于数据库设计。 (2) 逻辑模型 ,逻辑模型主要包括…

Mybatis实现分页查询数据(代码实操讲解)

在MyBatis中实现分页查询的常见方式有两种:使用MyBatis内置的分页插件如PageHelper,或者手动编写分页的SQL语句。下面我将为你提供两种方式的示例代码。 使用PageHelper分页插件 首先,确保你的项目中已经添加了PageHelper的依赖。在Maven项…

2023 2024年全国职业院校技能大赛中职组网络建设与运维赛项服务器Linux部分教程解析

欢迎合作 需要资料请私 Rocky 9 包含各种常考服务(包括新题型KVM等)

RabbitMQ是如何保证高可用的?

RabbitMQ可以通过多种方式来实现高可用性,以确保在硬件故障或其他不可预测的情况下,消息队列系统仍然能够正常 运行。RabbitMQ有三种模式:单机模式,普通集群模式,镜像集群模式。 其中单机模式一般用于demo搭建&#x…

unocss 究竟比 tailwindcss 快多少?

unocss 究竟比 tailwindcss 快多少? 前言 我们知道 unocss 很快,也许是目前最快的原子化 CSS 引擎 (没有之一)。 unocss 解释它为什么这么快的原因,是因为它不用去解析 CSS 抽象语法树,直接在 content 里面通过正则表达式从内容…

基本设计模式

单例模式 ES5 function Duck1(name:string){this.namenamethis.instancenull }Duck1.prototype.getNamefunction(){console.log(this.name) }Duck1.getInstancefunction(name:string){if(!this.instance){this.instance new Duck1(name)} } const aDuck1.getInstance(a) const…