Leetcode循环队列

news2025/7/19 4:31:22

这道题十分考验我们对队列的理解。

文章目录

      • 队列的介绍
      • 队列的实现
      • 进入正题

队列的介绍

队列是一种只允许在一段进行插入,在另一端进行删除的数据操作的特殊线性结构,,因此决定了他具有先入先出的特点,其中进行插入操作的一段叫做队尾,出队列的一端叫做队头。

在这里插入图片描述

队列的实现

队列可以使用链表或者数组进行实现,对于这两种实现方法,使用链表实现效果更好一点,两个指针中front为链表的头,即队列的队头,出数据的话只需要找到front的下一个假设为pre,将front销毁,front置为pre即可,如果是用数组的结构的话,出队列在数组头上出数据,效率会很低。
链表实现队列代码如下
Queue.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>


typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;


typedef struct Queue
{
	QNode* head;//头
	QNode* tail;//尾
	int size;//大小
}Que;
void QueueInit(Que* pq);//初始化
void QueuePush(Que* pq,QDataType);//入队列
void QueueDestroy(Que* pq);//销毁
void QueuePop(Que* pq);//出队列
QDataType QueueFront(Que* pq);//队头的数据
QDataType QueueBack(Que* pq);//队尾的数据

bool QueueEmpty(Que* pq);//检查是否为空
int QueueSize(Que* pq);//队列元素

Queue.c

#define _CRT_SECURE_NO_WARNINGS
#include "Queueh.h"

void QueueInit(Que* pq)
{
	assert(pq);

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueueDestroy(Que* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur != NULL)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;

}

void QueuePush(Que* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->next = NULL;
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;

	if (pq->tail == NULL)//这里要先进行判断
	{
		pq->head = pq->tail = newnode;//如果队列里没有一个元素
		//那么head和tail都为空,将newnode设置为队头,当然也是队尾,毕竟只有一个元素。
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

void QueuePop(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));//判空,避免引起不必要的错误。
	if (pq->head->next != NULL)
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	else
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	pq->size--;
}

QDataType QueueFront(Que* pq)
{
	assert(pq);
	//判断是否为空
	assert(!QueueEmpty(pq));
	return pq->head->data;//队头位置
}

QDataType QueueBack(Que* pq)
{
	assert(pq);
	//判断是否为空
	assert(!QueueEmpty(pq));
	return pq->tail->data;//队尾位置
}

bool QueueEmpty(Que* pq)//判断是否为空,为空则返回true
{
	if (pq->head == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int QueueSize(Que* pq)
{
	assert(pq);
	return pq->size;
}

进入正题

链接:设计循环队列
在这里插入图片描述

前边的队列如果空间不够就会扩容,但是这里的循环队列大小是固定的,只可以保存k个元素,当然还是遵循先入先出的规则

 例如下边的环形队列,在pop掉队头数据后,这块空间不会被销毁的,可以继续存储值覆盖原来的值,假设k等于5,当入6个元素后,这个循环队列就满了,当出队列时,此时这个队列的首位置就可以继续存储数据。
在这里插入图片描述
循环队列的思路和环形队列一样

那么这道题用数组实现比较好还是链表实现比较好呢?

我想你一定第一反应是用链表实现比较好,然而这道题相对于数组,链表实现就显得更加复杂一点
 因为这也是一个环状结构,刚好可以实现一个环形链表来实现,但是我们要注意的是,链表的两个指针的状态通常是左闭右开。
即 [front,tail)
在这里插入图片描述
再插入一个数据后,tail=tail->next。
在这里插入图片描述
可以发现,tail总是在有效数字的下一位置。

 和实现链表不同的地方是,链表的尾只有在开好后才会让tail指向尾节点,这里的链表长度是固定的,当一个元素入队列后,tail会指向下一个位置,如果是这样的话如何表示空和满呢?
 当最后插入一个数据后,tail指向下一个位置刚好是front,判断为满?但是当队列里没有元素的话,tail和front的位置也是相同的,当然,如果你定义一个size来判断当然可以。

然而还有一个更大的缺陷就是题目要求获取队尾元素,如果是单向链表的话,想要找放到tail的前一个结点还需要遍历一边才行,如果用双向链表的话也可以,但是就有点太大费周章了。

如果用数组来实现会简单许多滴!

结构体声明如下

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->k=k;
    obj->front=obj->rear=0;
    return obj;
}

在这里插入图片描述
数组也面临一个同样的问题,如何判断是满还是空?
可以多开一块空间。k==5,开6块空间,最后一块空间浪费不用。
在这里插入图片描述
如果front等于tail就为空,在这里设置tail的值为0~5(要注意下标和位置有减一的关系),如果tail的下一个位置为front时,表示队列已满。

obj->tail%=(obj->k+1);//obj为循环队列变量

控制tail的值的变化范围,当tail等于6时置tail为0。
当然,在出队列过程中,front是会不断变化的。
我们看front变化的情况
pop一个数据后,向后移一位
在这里插入图片描述

判断是否队列已满的条件判断句如下

(obj->tail+1)%(obj->k+1 )==obj->front

前边已经说过了,tail的变化范围为0~5,此时tail被置为0,但front为1,不相等,就表示还有空余的位置,队列没有满,所以上边的判断语句在任何场景都是正常使用的。

判断是否已满函数如下(题目中tail被rear替换)

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

返回类型为布尔值,如果相等就返回true,不相等就返回false。
判断是否为空很简单,直接比较rear和front的值是否相等即可。

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->rear;
}

置空函数

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

获取队头元素
很简单,返回front位置的元素即可

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

获取队尾元素
这里就要思考一下了
如果rear不在数组第一个空间上,直接返回数组rear-1处的值即可,当rear位于数组首元素,就要返回数组第k个元素。
代码如下

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        if(obj->rear==0)
        {
            return obj->a[obj->k];
        }
        else{
            return obj->a[obj->rear-1];
        }
		//下边是综合写法
        //return obj->a[(obj->rear+obj->k)%(obj->k+1)];
    }
}

出队列deQueue()
出队列只需要将front++即可,就算之前的数据不销毁,下次入队列操作也会覆盖他的数据。
代码如下

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

注意是要有返回值的,如果队列为空,就没有出数据,返回false,出数据成功就返回true。
入队列
代码如下:

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }

    obj->a[obj->rear]=value;
    obj->rear++;

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

    return true;
}

首先判断循环队列是否已满,如果已满就返回false,如果没有满就将rear位置的值改为value,然后rear++,判断是否超出范围,如果超出就置为0。最后入队列成功返回true。
 到了这里这道题目就顺利解决了,如果使用双向链表来做这道题的话当然也可以,但是会稍微麻烦一点,有兴趣可以尝试尝试。
今天的内容就到这里啦,如果有错误欢迎各位指正哦!
综合上述代码后即可通过本题。
在这里插入图片描述

全部代码如下




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->k=k;
    obj->front=obj->rear=0;
    return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->k+1  )==obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }

    obj->a[obj->rear]=value;
    obj->rear++;

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

    return true;
}

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

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

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

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



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);
*/

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

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

相关文章

MFC打开控制台的常用方式

工程项目中&#xff0c;想打开控制台的&#xff0c;简单打印日志 &#xff08;1&#xff09;依次打开&#xff1a; 项目配置属性——>生成事件——>后期生成事件&#xff1a;命令行 &#xff08;2&#xff09;输入&#xff1a; editbin /SUBSYSTEM:CONSOLE $(OUTDIR)\$…

pppoe拨号案例

R3服务端 interface LoopBack0 ip address 1.1.1.1 255.255.255.255 aaa local-user test password cipher admin local-user test service-type ppp ip pool test network 100.0.0.0 mask 255.255.255.0 interface Virtual-Template0 ppp authentication-mode chap remote …

【设计模式】第23节:行为型模式之“策略模式”

一、简介 策略模式&#xff1a;定义一族算法类&#xff0c;将每个算法分别封装起来&#xff0c;让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端&#xff08;这里的客户端代指使用算法的代码&#xff09;。 二、适用场景 动态选择算法多种类似的行为 …

CondConv 动态卷积学习笔记 (附代码)

论文地址:https://arxiv.org/abs/1904.04971 代码地址&#xff1a;https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet/condconv 1.是什么&#xff1f; CondConv是一种条件参数卷积&#xff0c;也称为动态卷积&#xff0c;它是一种即插即用的模块&…

数据结构之集合框架

1.Java集合框架的定义 Java 集合框架 Java Collection Framework &#xff0c;又被称为容器 container &#xff0c;是定义在 java.util 包下的一组接口 interfaces和其实现类 classes 。 其主要表现为将多个元素 element 置于一个单元中&#xff0c;用于对这些元素进行…

向上管理中的沟通技巧

一. 背景 我们要弄清楚两个问题为什么要向上管理呢&#xff0c;向上管理主要是要做什么呢&#xff1f; 首先&#xff0c;第一个问题为什么要向上管理&#xff1f;向上管理的本质是为了同时给公司、上司和自己带来最好的结果&#xff0c;并有意识地配合和改变工作方法&#xf…

iPhone连不上Wi-Fi?看完这篇文章你就知道了!

大家在使用苹果手机的过程中有没有遇到过这样的情况&#xff1a;手机突然连接不上Wi-Fi&#xff0c;或者连接了也根本使用不了。遇到上述情况请不要着急&#xff0c;iphone连不上wifi是由很多种原因导致的。那么&#xff0c;iPhone连接不上Wi-Fi时该怎么办呢&#xff1f; 我们…

测试可用的安防视频分析软件:烟火检测、车型检测、玩手机打电话检测、厨帽检测、抽烟检测、人员入侵检测

下载地址&#xff1a;https://pan.baidu.com/s/1R1MvD_KQ3uB-0KL_N3is-w?pwdwa33 随着AI、大数据、云计算和边缘计算等技术的迅猛发展&#xff0c;我国的视频监控市场正处于全新的阶段。借助AI深度学习技术的进步&#xff0c;现代化的安防视频监控系统通过边缘计算设备上的AI识…

用友NC BeanShell RCE漏洞

一、漏洞简介 用友 NC 是面向集团企业的管理软件&#xff0c;其在同类市场占有率中达到亚太第一。用友 NC 由于对外开放了 BeanShell 接口&#xff0c;攻击者可以在未授权的情况下直接访问该接口&#xff0c;并构造恶意数据执行任意代码从而获取服务器权限。 二、影响版本 NC …

误删的文件不在回收站如何找回?分享3个简单方法!

“我前段时间清理电脑的时候误删了一些比较重要的文件&#xff0c;通常我都会使用回收站来还原这些文件的&#xff0c;但昨天不小心清空了回收站&#xff0c;想问问还有机会找回我的文件吗&#xff1f;” 为了保证用户的权益&#xff0c;误删的文件通常会先被移入电脑回收站中。…

SpringBootWeb案例——Tlias智能学习辅助系统(1)

目录 需求与准备环境搭建REST风格的API接口开发规范-统一响应结果 部门管理部门列表查询功能删除部门新增部门请求路径优化查询部门修改部门 员工管理分页查询分页插件PageHelper分页查询(带条件) (难点)删除员工 需求与准备 1、部门管理 包括&#xff1a; 查询部门列表 删除部…

解决远程连接数据库缓慢的问题【图文】【非常详细】

问题概述 当我们远程访问数据库&#xff0c;遇到连接不上或者连接等待时间较长&#xff0c;问题大概率就出在数据库远程链接解析的问题&#xff0c;就是在MySQL的配置文件中增加如下配置参数&#xff1a; [mysqld] skip-name-resolve 具体操作如下 解决步骤 打开mysql所在文…

中小企业选择外贸管理系统有哪些常见的误区?

中小企业基础设施相对薄弱、人员管理松散&#xff0c;选择外贸管理系统是很多管理者的解决方案。选型系统不是一蹴而就的&#xff0c;其中会遇到很多问题甚至进入误区&#xff0c;那么中小企业选择外贸管理系统有哪些常见的误区&#xff1f; 本地部署比云服务更安全 CRM数据安…

【唠唠嵌入式】__如何学习单片机?

目录 前言 个人定位&#xff0c;从事软件还是硬件&#xff1f; 学习内容 (*&#xffe3;︶&#xffe3;)创作不易&#xff01;期待你们的 点赞、收藏和评论喔。 前言 作为一个老司机&#xff0c;多年来跟单片机、Keil、C语言、AD、烙铁、风枪、示波器、电子元器件纠缠不清…

【机器学习】五、贝叶斯分类

我想说&#xff1a;“任何事件都是条件概率。”为什么呢&#xff1f;因为我认为&#xff0c;任何事件的发生都不是完全偶然的&#xff0c;它都会以其他事件的发生为基础。换句话说&#xff0c;条件概率就是在其他事件发生的基础上&#xff0c;某事件发生的概率。 条件概率是朴…

获取Webshell方法

CMS系统指的是内容管理系统。已经有别人开发好了整个网站的前后端&#xff0c;使用者只需要部署cms&#xff0c;然后通过后台添加数据&#xff0c;修改图片等工作&#xff0c;就能搭建好一个的WEB系统。 CMS获取Webshell方法 WordPress后台拿Webshell phpcms拿Webshell 非CMS…

Vue:实现复制按钮功能

作者:CSDN @ _乐多_ 本文记录了vue开发中,复制按钮的实现代码。用于复制网页中的一个数或者字符串啥的。 效果如下图所示, 文章目录 <el-button @click="copyToClipboard(wgs84Position2.altitude)">复制</el-button>data(

AI赋能,轻松出爆文!AI新闻创作新时代,你准备好了吗?

众所周知&#xff0c;传统新闻报道需要大量的人工参与&#xff0c;不仅耗时耗力&#xff0c;还对媒体工作者的文字功底和知识积累有很高的要求。但随着人工智能技术的发展&#xff0c;大模型在新闻写作领域展现出强大的潜力。通过AI写作技术&#xff0c;在很大程度上实现了新闻…

小程序商城免费搭建之java商城 电子商务Spring Cloud+Spring Boot+二次开发+mybatis+MQ+VR全景+b2b2c

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

第二证券:深圳规划建设中心城区1公里超充圈

大湾区之声消息&#xff0c;本年《深圳市新能源轿车超充设备专项规划》发布&#xff0c;明晰了深圳“超充之城”制作的“路线图”。现在&#xff0c;深圳累计建成超充站41座&#xff0c;还有11座超充站正在制作中。到2023年年末&#xff0c;争夺建成不少于150座共用超充站&…