设计循环队列

目录

设计循环队列

🙂【1】数组循环队列

思路分析

❓1

❓2

❓3

易错总结

创建MyCircularQueue

初始化myCircularQueueCreate

为空否myCircularQueueIsEmpty

为满否myCircularQueueIsFull

插入元素myCircularQueueEnQueue

删除元素myCircularQueueDeQueue

获取首元素myCircularQueueFront

获取尾元素myCircularQueueRear

释放空间myCircularQueueFree

🆗【1】总代码

🙂【2】链表循环队列 

思路分析

易错总结 

创建MyCircularQueue

初始化myCircularQueueCreate

为空否myCircularQueueIsEmpty

为满否myCircularQueueIsFull

插入元素myCircularQueueEnQueue

删除元素myCircularQueueDeQueue

获取首元素myCircularQueueFront

获取尾元素myCircularQueueRear

释放空间myCircularQueueFree

🆗【2】总代码


另外扩展了解一下,实际中我们有时还会使用一种队列叫【循环队列】。如操作系统讲解【生产者消费者模型】时可以就会使用循环队列。环形队列可以使用【数组】实现,也可以使用循环【链表】实现。我们今天来实现一下。

设计循环队列

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

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

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

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

 

🙂【1】数组循环队列

 

这个【数组循环队列】在逻辑上是如上图所示,但是在物理上,不是循环的。所以特别注意:关于数组循环的这个点,我们必须手动控制。 

思路分析

❓1

空和放一个元素怎么区分?

  • 方法1:back初始化为0,指向队尾元素的下一个位置。
  • 方法2:back初始化为-1,指向队尾元素。 
  • 特别提醒!:用方法1比较好控制

 

❓2

空和满怎样去区分(用方法1区分空和一个元素)?

  • 方法1:设置size。
  • 方法2:malloc多一个空间,不放置元素。(k+1)
  • 以上两者方法都可以。

❓3

怎么处理数组物理上不循环(改成逻辑上循环)?

  • (back+1)%(k+1) = fron
  • obj->back %= obj->k+1
  • return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)]

这里是以判空和满的来讲解,其他的插入和取尾元素是同理的!! 

易错总结

  • 临时变量出了函数就销毁了,必须malloc
  • A%B(A>B对A来说是没有任何影响,A<=B对A来说模去多余的B)---用来处理数组回绕地方
  • 操作符优先级 所以最好都加上括号
  • 处理的表达式的左边不能为计算式(❌obj->front+1%=obj->k+1;)
  • 判空和满直接下标运算即可,不用用数组(为什么不能用数组❓)
  • 释放空间先释放数组空间,在释放myCircularQueue

创建MyCircularQueue

//用数组实现+多开辟一个空间不放元素
typedef struct {
    int*a;
    int front;
    int back;//数组下标
    int k;//循环队列的最多放置数据
} MyCircularQueue;

初始化myCircularQueueCreate

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    int*tmp=(int*)malloc(sizeof(int)*(k+1));//多开辟一个空间
    obj->a=tmp;
    obj->front=0;
    obj->back=0;//指向最后一个元素的下一个
    obj->k=k;
    return obj;
}

为空否myCircularQueueIsEmpty

//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front == obj->back;//==0 
}

为满否myCircularQueueIsFull

//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->back+1) % (obj->k+1) == obj->front;//back+1=front
    //操作符优先级问题
}

插入元素myCircularQueueEnQueue

 考虑下这个特殊情况!

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))//true 满了
    {
        return false;
    }
        obj->a[obj->back] = value;
        obj->back++;
        obj->back %= obj->k+1;//处理
        //obj->front+1%=obj->k+1;//处理左边不能为计算表达式
       return true;
}

删除元素myCircularQueueDeQueue

  考虑下这个特殊情况!

//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        obj->front++;
        obj->front%=obj->k+1;//处理
        return true;
    }
}

获取首元素myCircularQueueFront

//获取首元素
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    return obj->a[obj->front];
}

获取尾元素myCircularQueueRear

  考虑下这个特殊情况!

//获取尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    //return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)];
    return obj->a[(obj->back+obj->k)%(obj->k+1)];
}

释放空间myCircularQueueFree

//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
    obj=NULL;
}

🆗【1】总代码

//用数组实现+多开辟一个空间不放元素
typedef struct {
    int*a;
    int front;
    int back;//数组下标
    int k;//循环队列的最多放置数据
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    int*tmp=(int*)malloc(sizeof(int)*(k+1));//多开辟一个空间
    obj->a=tmp;
    obj->front=0;
    obj->back=0;//指向最后一个元素的下一个
    obj->k=k;
    return obj;
}
//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front == obj->back;//==0 
}

//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->back+1) % (obj->k+1) == obj->front;//back+1=front
    //操作符优先级问题
}

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))//true 满了
    {
        return false;
    }
        obj->a[obj->back] = value;
        obj->back++;
        obj->back %= obj->k+1;//处理
        //obj->front+1%=obj->k+1;//处理左边不能为计算表达式
       return true;
}

//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        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
    //return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)];
    return obj->a[(obj->back+obj->k)%(obj->k+1)];
}

//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
    obj=NULL;
}

🙂【2】链表循环队列 

链表很简单对于处理循环的问题,只要实现单项循环链表即可。这里的难点就是:(1)创建单项循环链表。(2)找到back的前一个元素

思路分析

关于判【空/一个元素】& 判【空/满】都是和上面数组是一样的。这里不过多阐述。

怎么去找到back的前一个元素?

其实这个问题在我们前面博文实现链表也详细讲解,相信大家可以轻松掌握!!

        Node*prev=obj->front;
        while(prev->next != obj->back)
        {
            prev=prev->next;
        }

易错总结 

  • 初始化一定要把back置回开头
  • 找back前一个元素:要么用三个指针,要么遍历一遍链表。
  • 释放空间不能遍历去释放,会造成野指针。
  • 释放空间先把循环链表改变成单向链表,才能循环遍历释放。 

创建MyCircularQueue

typedef struct Node
{
    int val;
    struct Node*next;
}Node;//节点

typedef struct {
    Node*front;
    Node*back;    
    int size;//计算放入队列的元素个数
} MyCircularQueue;//循环队列

初始化myCircularQueueCreate

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->front=NULL;
    obj->back=NULL;
    while(k--)
    {
            Node*newnode=(Node*)malloc(sizeof(Node));
            if(obj->front == NULL)
            {
                obj->front=obj->back=newnode;
                obj->front->val=0;
            }
            else
            {
                obj->back->next=newnode;
                obj->back=newnode;
                obj->back->val=0;
            }
    }
    //循环
    obj->back->next=obj->front;
    //back
    obj->back=obj->front;
    //
    obj->size=0;
    return obj;
}

为空否myCircularQueueIsEmpty

//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if(obj->size == 0 && obj->front == obj->back)
    return true;
    else
    return false;
}

为满否myCircularQueueIsFull

//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if(obj->size != 0 && obj->front == obj->back)
    return true;
    else
    return false;
}

插入元素myCircularQueueEnQueue

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))//true 满了
    {
        return false;
    }
    else
    {
        obj->back->val=value;
        obj->back=obj->back->next;
        obj->size++;
        return true;
    }
}

删除元素myCircularQueueDeQueue

//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        obj->front=obj->front->next;//❌易错
        obj->size--;
        return true;
    }
}

获取首元素myCircularQueueFront

//获取首元素
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->front->val;
}

获取尾元素myCircularQueueRear

//获取尾元素
int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    //❌易错
    else
    {
        Node*prev=obj->front;
        while(prev->next != obj->back)
        {
            prev=prev->next;
        }
        return prev->val;
    }
}

释放空间myCircularQueueFree

//释放空间
//❌易错
void myCircularQueueFree(MyCircularQueue* obj) {
    Node*prev=obj->front;
    while(prev->next != obj->front)
    {
        prev=prev->next;
    }
    //prev是最后一个
    prev->next=NULL;
    //
    while(obj->front->next != NULL)
    {
        Node*tmp=obj->front;
        obj->front=obj->front->next;
        free(tmp);
        tmp=NULL;
    }
    free(obj->front);
    obj->front=NULL;
    free(obj);
    obj=NULL;
}

🆗【2】总代码

typedef struct Node
{
    int val;
    struct Node*next;
}Node;//节点

typedef struct {
    Node*front;
    Node*back;    
    int size;//计算放入队列的元素个数
} MyCircularQueue;//循环队列


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->front=NULL;
    obj->back=NULL;
    while(k--)
    {
            Node*newnode=(Node*)malloc(sizeof(Node));
            if(obj->front == NULL)
            {
                obj->front=obj->back=newnode;
                obj->front->val=0;
            }
            else
            {
                obj->back->next=newnode;
                obj->back=newnode;
                obj->back->val=0;
            }
    }
    //循环
    obj->back->next=obj->front;
    //back
    obj->back=obj->front;
    //
    obj->size=0;
    return obj;
}


//判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if(obj->size == 0 && obj->front == obj->back)
    return true;
    else
    return false;
}

//判断是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if(obj->size != 0 && obj->front == obj->back)
    return true;
    else
    return false;
}

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))//true 满了
    {
        return false;
    }
    else
    {
        obj->back->val=value;
        obj->back=obj->back->next;
        obj->size++;
        return true;
    }
}

//删除元素
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        obj->front=obj->front->next;
        obj->size--;
        return true;
    }
}

//获取首元素
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->front->val;
}

//获取尾元素
int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        Node*prev=obj->front;
        while(prev->next != obj->back)
        {
            prev=prev->next;
        }
        return prev->val;
    }
}

//释放空间
void myCircularQueueFree(MyCircularQueue* obj) {
    Node*prev=obj->front;
    while(prev->next != obj->front)
    {
        prev=prev->next;
    }
    //prev是最后一个
    prev->next=NULL;
    //
    while(obj->front->next != NULL)
    {
        Node*tmp=obj->front;
        obj->front=obj->front->next;
        free(tmp);
        tmp=NULL;
    }
    free(obj->front);
    obj->front=NULL;
    free(obj);
    obj=NULL;
}

 还有数据结构的【栈】和操作系统的【栈】是不一样的。数据结构的【栈】是一种线性表。操作系统的【栈】是内存的区域,会发生栈溢出和内存泄露的问题(递归程序/返回条件有问题),但是数据结构【栈】不会。

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!

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

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

相关文章

[原创][3]探究C#多线程开发细节-“用ConcurrentQueue<T>解决多线程的无顺序性的问题“

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XXQQ: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delphi…

C++17那些事开篇之类模版参数推导(CTAD)

C17那些事开篇之类模版参数推导(CTAD) 引入 大家好&#xff0c;我是光城&#xff0c;今天开始正式开篇C17的新特性了&#xff0c;期待不&#xff0c;欢迎留言区说出想要更新的特性呀&#xff5e; C模板元编程一直是C开发者们熟知的一项功能&#xff0c;无论是初学者还是高级开发…

java springboot通过application配置文件生成随机值并控制范围

我们找到 项目的 application 配置文件 这里我们还是习惯用 yml格式的 我们在配置文件中 写出 ${random.} 的时候 他就会将所有可配置的随机类型都提示出来了 有 整数 长整星 字符串 uuid 这里 我们来个模板 testcase:book:id: ${random.int}name: ${random.value}date: ${r…

kubernetes(K8s)(Namespace、Pod、Deployment、Service资源的基本操作)-04

Namespace Namespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 默认情况下&#xff0c;kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中&#xff0c;可能不想让两个Pod之间进行互相的…

智跃人力资源管理系统 SQL注入漏洞复现

0x01 产品简介 智跃人力资源管理系统是基于B/S网页端广域网平台&#xff0c;一套考勤系统即可对全国各地多个分公司进行统一管控&#xff0c;成本更低。信息共享更快。跨平台&#xff0c;跨电子设备 0x02 漏洞概述 智跃人力资源管理系统GenerateEntityFromTable.aspx接口处存在…

机器人RL数据集探索

机器人RL数据集探索 相关资料汇总 相关资料汇总

传统家装“死气沉沉”?VR智慧家装提供VR可视化方案

传统家装市场虽然处于成熟期&#xff0c;但是对于装修小白的户主来说&#xff0c;难以解决的痛点依旧还有很多。很多家装公司所谓的设计师&#xff0c;不一定全都具备设计知识&#xff0c;也不懂得从客户的需求出发&#xff0c;多重因素导致家装行业“死气沉沉”。 为了打破装修…

快速排序并不难

快速排序的核心框架是“二叉树的前序遍历对撞型双指针”。我们在《一维数组》一章提到过”双指针思路“&#xff1a;在处理奇偶等情况时会使用两个游标&#xff0c;一个从前向后&#xff0c;一个是从后向前来比较&#xff0c;根据结果来决定继续移动还是停止等待。快速排序的每…

uc_12_进程间通信IPC_有名管道_无名管道

1 内存壁垒 进程间天然存在内存壁垒&#xff0c;无法通过交换虚拟地址直接进行数据交换&#xff1a; 每个进程的用户空间都是0~3G-1&#xff08;32位系统&#xff09;&#xff0c;但它们所对应的物理内存却是各自独立的。系统为每个进程的用户空间维护一张专属于该进程的内存映…

【每日一题】1657. 确定两个字符串是否接近-2023.11.30

题目&#xff1a; 1657. 确定两个字符串是否接近 如果可以使用以下操作从一个字符串得到另一个字符串&#xff0c;则认为两个字符串 接近 &#xff1a; 操作 1&#xff1a;交换任意两个 现有 字符。 例如&#xff0c;abcde -> aecdb操作 2&#xff1a;将一个 现有 字符的…

linux 消息队列apache-activemq服务的安装

1.下载 官网下载地址&#xff1a;https://activemq.apache.org/ 操作如下&#xff1a; 2. 解压 执行&#xff1a;tar -zxvf apache-activemq-5.18.3-bin.tar.gz -C /user/ 3. 进入目录 执行&#xff1a;cd /user/apache-activemq-5.18.3 4.修改配置文件 执行&#xff1…

物流实时数仓ODS层——Mysql到Kafka

目录 1.采集流程 2.项目架构 3.resources目录下的log4j.properties文件 4.依赖 5.ODS层——OdsApp 6.环境入口类——CreateEnvUtil 7.kafka工具类——KafkaUtil 8.启动集群项目 这一层要从Mysql读取数据&#xff0c;分为事实数据和维度数据&#xff0c;将不同类型的数据…

王道数据结构课后代码题p40 4.在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值唯一) (c语言代码实现)

本题代码为 void deletemin(linklist* L)//找到最小值并删除 {lnode* p (*L)->next, * pre *L;lnode* s p,*sprepre;while (p ! NULL)//找到最小值{if (p->data < s->data){s p;spre pre;}p p->next;pre pre->next;}p s->next;spre->next p;…

「黄钊的AI日报·第二季」早鸟票,最后48小时~

每天5条AI内容点&#xff1a;不是新闻汇总&#xff0c;而是站在11年AI产品经理的视角&#xff0c;将原AI信息中的干货认知&#xff0c;提炼成我自己的文字、展示“what I see”。 做社群“AI产品经理大本营”6年以来&#xff0c;我都是在非常用心的输出AI干货&#xff1b;这份“…

时序预测 | Python实现TCN时间卷积神经网络价格预测

时序预测 | Python实现TCN时间卷积神经网络时间序列预测 目录 时序预测 | Python实现TCN时间卷积神经网络时间序列预测预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 时间卷积网络,TCN。 利用CNN技术处理时间序列数据。 卷基础层有三种,第一种是一维CNN,用于输…

Python语言学习笔记之七(JOSN应用)

本课程对于有其它语言基础的开发人员可以参考和学习&#xff0c;同时也是记录下来&#xff0c;为个人学习使用&#xff0c;文档中有此不当之处&#xff0c;请谅解。 1、认识Json JSON (JavaScript Obiect Notation)是一种轻量级的数据交换格式&#xff0c;它是ECMAScript的一…

python高级练习题库实验1(A)部分

文章目录 题目1代码实验结果题目2代码实验结果题目3代码实验结果题目4代码实验结果题目总结题目1 输入一个整数,用于控制输出*的个数,输入日期,按照特定格式输出 研究下面的例子,并编写一个与这些例子完全相同的程序。 代码 import datetime# ask user for length of b…

ZPLPrinter Emulator SDK for .NET 6.0.23.1123​ Crack

ZPLPrinter Emulator SDK for .NET 适用于 .NET 的 ZPLPrinter 仿真器 SDK 允许您通过编写 C# 或VB.NET 代码针对任何 .NET Framework、.NET CORE、旧版 ASP.NET MVC 和 CORE、Xamarin、Mono 和通用 Windows 平台 (UWP) 作业。 适用于 .NET 的 ZPLPrinter 仿真器 SDK 允许您将…

ubuntu0.22.04.1安装mysql8.0及root密码注意

先看一下你的安装包是什么版本 apt list |grep mysql基本都是默认的8.0版本&#xff0c;然后安装&#xff1a; apt-get install mysql-server-8.0安装以后 &#xff0c;mysql默认启动&#xff1b; 一般root 是没有密码的&#xff0c;在本地直接回车登录 我们看一下密码插件 …

Kubernetes(K8s)_15_CNI

Kubernetes&#xff08;K8s&#xff09;_15_CNI CNI网络模型UnderlayMAC VLANIP VLANDirect Route OverlayVXLAN CNI插件FlannelCalico CNI配置内置实现 CNI CNI(Container Network Interface): 实现容器网络连接的规范 Kubernetes将网络通信可分为: Pod内容器、Pod、Pod与Se…