力扣622:设计循环队列(中等)

这篇具有很好参考价值的文章主要介绍了力扣622:设计循环队列(中等)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

思考

一,循环队列的初始化myCircularQueueCreate

二,判断是否为空myCircularQueueIsEmpty

三,判断队列是否满了bool myCircularQueueIsFull

四,队列的插入myCircularQueueEnQueue

五,队列的删除myCircularQueueDeQueue

六,队列取头元素和尾元素myCircularQueueFront   //   myCircularQueueRear

七,销毁队列myCircularQueueFree

本题要点

完整答案


一般我们入手的队列都是单项不循环的,所以我们会更倾向于选择用链表来实现,并且会选择单链表来简化队列先入先出的规则,但是这个题可能会颠覆你的认知

力扣622:设计循环队列(中等),leetcode,算法

力扣622:设计循环队列(中等),leetcode,算法

我们再来看看chargpt3.5给出的循环队列的演示图(足够细致了):

力扣622:设计循环队列(中等),leetcode,算法

思考

这个题要我们从0开始实现循环队列,那再用单链表就不太可能了,因为循环不了嘛。这个时候脑洞比较大的人比如我,就会想到很早做过的约瑟夫环,单项循环链表,带不带头无所谓的(带头反而浪费空间)。

方案一:用单项循环链表。

可不可行呢,是循环了,但是不知道你们有没有注意到函数的接口有一个Rear(获取队尾元素),单项的链表获取队尾元素是不是比较困难,还不如双向循环链表。

那可不可以换成用双向循环链表来弥补单项的不足呢!

方案二:用双向循环链表

可以是解决了取为难的问题,但是链表的结点是不是要一个一个创建再连接起来,连成k个,那链表实现的困难就是初始化困难很多,需要前后链接。再者,如果用链表来实现也不好判断到底这个队列是空的还是满的,因为循环了嘛。

方案三:用数组

在我们的众多讨论之下,选择了用数组来实现,优势1:数组的数据是连续的(参考顺序表),不需要去一个一个链接。优势2:处理起来更简单,增删改等操作都简单。

然后我们用类似之前双指针的思路,设置一个Front为数组的开头元素的序号,一个Rear为数组的结尾元素的序号,来判断数组是否空和满,但是这个Rear应该指向尾元素的下一个位置来。

因为,如果Rear不指向下一个元素那么当队列只有有一个元素的情况下Rear和Front的值是相同的,没有元素的情况下(初始化)也是相同的。就无法判断了。

我们选定了方法,也有了思路,那就来实现一下这个题:

一,循环队列的初始化myCircularQueueCreate

力扣622:设计循环队列(中等),leetcode,算法

这里说一下为什么要多创造一个空间,主要是来好判断队列满了的情况,后面会解释的。

为什么obj也要创建一个空间呢,我们直接在实现顺序表时都没有这样操作呀,那是因为由于obj这个结构体是在创建函数之外创建的,这个函数的参数没有这个结构体,也就是说这个obj是创建在栈区了,出了函数就销毁了,malloc是重新创建在堆区的,只要程序不结束就不会消失,所以就要重新创建空间。所以如果直接写:

MyCircularQueue obj;    //……   //  return &obj;,这样obj作为函数里的临时变量,出函数就被销毁了,取地址再返回也是不行的!!!

二,判断是否为空myCircularQueueIsEmpty

力扣622:设计循环队列(中等),leetcode,算法

力扣622:设计循环队列(中等),leetcode,算法

红色的为空出来的空间,也就是多创建的空间,如图其实不难发现不管是有元素还是没有元素,rear循环了还是没有循环,rear+1都==front。

三,判断队列是否满了bool myCircularQueueIsFull

力扣622:设计循环队列(中等),leetcode,算法

这里解释一下为什么要多开辟一个空间来解决伪充满的问题!!!

力扣622:设计循环队列(中等),leetcode,算法

如图,当rear的值增大到6时由于要循环,所以rear%k = 0,为了让数组循环起来,%数组的大小是最好的选择,此时如果(rear + 1)% k = 1,这样永远都不会等于front,无法判断,如果rear不加上1直接去%,那么rear%k = 0 = front这样无法判断队列是空的还是满的。

如果不让rear指向尾元素的下一个,直接指向尾元素,这样的话,当rear等于5时,最后一个数据进入队列,这样手动将rear+1 = 6,(rear + 1)% k = 0 = front;但是如果在进数据时有数据被取出,那front就不是等于0,有可能等于1,2……这样,front和rear依然不相等呀。

所以,多创建一个空间就是最好的选择:由图可知:rear+1 == front,由于在不循环的情况时,rear+1一定不会大于k+1的所以%(k+1)也不会影响不循环的情况的,循环时为了防止rear一直加后越界,所以要%(k+1),这就是数组循环的条件!

四,队列的插入myCircularQueueEnQueue

力扣622:设计循环队列(中等),leetcode,算法

插入时需要先判断队列是否为满的情况。

如果rear此时等于k时,如果前面没有足够的空位,那就需要考虑循环的问题就要%(k+1),不然就会越界访问。如果没有循环的问题那只需要插入在rear的位置就行,这个空格会一直出现在front的后面用以判断是否满了,空格就是多出来的空间。

力扣622:设计循环队列(中等),leetcode,算法

五,队列的删除myCircularQueueDeQueue

力扣622:设计循环队列(中等),leetcode,算法

力扣622:设计循环队列(中等),leetcode,算法

删除则要考虑队列是否为空。剩下的思路和上面的插入差不多!!!

六,队列取头元素和尾元素myCircularQueueFront   //   myCircularQueueRear

力扣622:设计循环队列(中等),leetcode,算法

取头尾元素都要先考虑队列是否为空,但是由于取头元素只要a[obj->Front],因为front没有什么变化,都对应着要取的数,那取尾会不会一样呢?

细心的你当然会发现肯定不是,如果没有循环是这样没错,但是如果rear循环就不一样了。

力扣622:设计循环队列(中等),leetcode,算法

如图,如果rear循环,那正常rear-1就是尾,但是如果rear=0,那rear+1=-1,所以需要加上一个队列的大小(k+1)使其转正后再%(k+1),%(k+1)是为了防止rear越界,即使是不循环或者循环且rear不等于0的情况,加上一个队列的大小再%这个队列的大小值也是不变的。上图的算数式可以更好的证明!!!

七,销毁队列myCircularQueueFree

力扣622:设计循环队列(中等),leetcode,算法

为什么不直接free(obj)呢?

分析obj的结构可得,因为obj这个结构体里面有a数组,如果直接free(obj),是只把obj所占的空间销毁了,但是里面的a数组的空间没有被销毁。

本题要点

本题主要是对于rear和front在移动时会不会越界的判断,和循环数组的处理方式(%(k+1)),rear-1越界的处理方式(+(k+1)),还需要更细致的判断能力和理解循环队列的循环结构。难度中等实至名归

完整答案

这样本题就解析+解答结束。下面为完整的解答过程。

typedef struct {

    int Front;

    int Rear;

    int* a;

    int capacity;

} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k)

{

    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));

    obj->Front = 0;

    obj->Rear = 0;

    obj->capacity = k + 1;

    obj->a = (int*)malloc(sizeof(int) * obj->capacity);

    return obj;

}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {

    if ((obj->Rear+1) % obj->capacity == obj->Front)

    {

        return false;

    }

    else

    {

        obj->a[obj->Rear] = value;

        obj->Rear = obj->Rear+1;

        obj->Rear = obj->Rear % obj->capacity;

        return true;

    }

}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {

    if (obj->Rear == obj->Front) {

        return false;

    }

    obj->Front = (obj->Front + 1) % obj->capacity;

    return true;

}

int myCircularQueueFront(MyCircularQueue* obj) {

    if (obj->Rear == obj->Front) {

        return -1;

    }

    return obj->a[obj->Front];

}

int myCircularQueueRear(MyCircularQueue* obj)

{

    if (obj->Rear == obj->Front)

    {

        return -1;

    }

    else

    {

        return obj->a[(obj->Rear-1 + obj->capacity) % obj->capacity];

    }

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {

    return obj->Rear == obj->Front;

}

bool myCircularQueueIsFull(MyCircularQueue* obj) {

    return (obj->Rear+1) % obj->capacity == obj->Front;

}

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

*/文章来源地址https://www.toymoban.com/news/detail-839108.html

到了这里,关于力扣622:设计循环队列(中等)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构:循环队列的实现(leetcode622.设计循环队列)

      目录 一.循环队列简单介绍 二.用静态数组实现循环队列 1.数组循环队列结构设计 2.数组循环队列的堆区内存申请接口  3.数据出队和入队的接口实现 4.其他操作接口 5.数组循环队列的实现代码总览  三.静态单向循环链表实现循环队列  1.链表循环队列的结构设计 2.创建静态

    2024年02月03日
    浏览(27)
  • 【刷题】622. 设计循环队列

    622. 设计循环队列 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一

    2024年02月05日
    浏览(30)
  • 力扣设计循环队列

    目录 1.使用了数组来表达循环 2.循环队列是否为空 3.循环队列是否已满。 4.初始化 5.向循环队列插入一个元素。如果成功插入则返回真                          6.从队首获取元素。如果队列为空,返回 -1                                  7.获取队尾元素。如果队列为

    2024年02月07日
    浏览(24)
  • 数据结构刷题训练:设计循环队列(力扣OJ)

    目录 文章目录 前言 1. 题目:设计循环队列 2. 思路 3. 分析  3.1 定义循环队列  3.2 创建队列  3.3 判空和判满  3.4 入队  3.5 出队  3.6 取队头队尾数据  3.7 销毁队列  4. 题解 总结         当谈到队列数据结构时,很多人可能会想到普通的队列,即先进先出(FIFO)的数据结

    2024年02月13日
    浏览(35)
  • leetcode——设计循环队列

    设计循环队列 这个题目在这里小编只分享一个解题思路,因为还有一个思路小编还在尝试,一直过不了,还在这里不断尝试,等我试出来的时候我在分享给大家,首先我们在这里给出的是数组的形式,后面在分享单链表的思路,因为数组在内存上是连续的,这里给出的思路是

    2024年02月05日
    浏览(25)
  • 【数据结构】如何设计循环队列?图文解析(LeetCode)

    LeetCode链接:622. 设计循环队列 - 力扣(LeetCode) 目录 做题思路 只开辟 k 个空间 多开一个空间 代码实现 1. 循环队列的结构 2. 开辟空间 3. 判断空 4. 判断满 5. 队尾插入数据 6. 队头删除数据 7. 获取队头元素 8. 获取队尾元素 9. 销毁队列 全部代码 设计循环队列,使用数组或链表

    2024年02月10日
    浏览(30)
  • leetcode 622. 设计循环链表

    这道题讲了两种方法,第一个代码是用数组实现的,第二个是用链表实现的,希望对你们有帮助 (最好在VS自己测试一遍,再放到 leetcode上哦) 下面的是主函数(作参考),静下心来慢慢测试 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先

    2024年02月05日
    浏览(25)
  • 【LeetCode力扣】11. 盛最多水的容器 (中等)

      目录 1、题目介绍 2、解题 2.1、解题思路  2.2、图解说明  2.3、解题代码 原题链接: 11. 盛最多水的容器 - 力扣(LeetCode) 示例 2: 提示: n == height.length 2 = n = 105 0 = height[i] = 104 这道题最优的方法就是用双指针,我们可以用指针 left 和指针 right 分别指向数组 height[ ] 的第一

    2024年02月06日
    浏览(36)
  • 【数据结构与算法】设计循环队列

      🧑‍🎓 个人主页:简 料   🏆 所属专栏:C++   🏆 个人社区:越努力越幸运社区   🏆 简       介: 简料简料,简单有料~在校大学生一枚,专注C/C++/GO的干货分享,立志成为您的好帮手 ~ C/C++学习路线 (点击解锁) ❤️ C语言阶段(已结束) ❤️ 数据结构与算法(ing) ❤

    2024年01月17日
    浏览(33)
  • 【数据结构与算法】用队列实现栈&&用栈实现队列&&设计循环队列

    🌠 作者:@ 阿亮joy. 🎆 专栏:《数据结构与算法要啸着学》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、

    2024年01月20日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包