【每日一题】设计循环队列(C语言)

循环队列是我们可以对队列有更深一步的理解的题目,而且可以进一步加强其他方面的知识(例如对循环数组的取模运算,指针的解引用),是个蛮不错的巩固习题,话不多说,进入正题。

链接在此:设计循环队列

强烈建议先自己做一遍,直接看的话可能会比较不知所云

目录

本题可以使用 数组或链表 来设计,本篇文章都会涉及到
做这题时会遇到很多难点
先说结论:此题的难点在于如何判断数组的 空与满 ,不管是链表还是数组,实现此问题都是难点。
在数据结构中,我们通常在解决此问题时都是选择多设置一个位置,back指向当前元素的下一个。
但多出来的位置不是不用,例如:

这样可以比较好的解决此类问题。

利用数组设计:

思路:

已经有了上述的前置知识

我们就可以比较轻易地判断空与满,数组中的frontback下标 指向同一个位置时是空,那么什么时候会满呢?

back的下一个为front时就为满,即back+1 == front

但是如果backfront后边,就需要我们的比较灵活的运用取模运算

在上边我们说到back+1 == front时为满,但是在上图中,我们发现back+1并不是front,而是超出了数组,

我们说过,会定义N+1个空间,N是元素个数,经过思考,我们会发现N就是back的下标,N+1就是back+1位置的下标,

那我们(back + 1)% (N + 1) == front时就是满

代码中剩下的取模运算也都大同小异

代码实现:

注意:我将代码中的判断空或满拿到了前边,防止使用时需要声明

c 复制代码
typedef struct {
    int* arr;
    int front;
    int rear;
    int N;
} MyCircularQueue;

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

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

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* ret = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    ret->arr = (int*)malloc(sizeof(int)*(k+1));
    ret->front = 0;
    ret->rear = 0;
    ret->N = k;
    return ret;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->arr[obj->rear] = value;
    obj->rear++;
    //防止rear出界
    obj->rear %= (obj->N + 1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    //防止front出界
    obj->front %= (obj->N + 1);
    return true;
}

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

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    //此处可以不用取模,if与else判断也可以
    return obj->arr[(obj->rear-1+(obj->N+1))%(obj->N+1)];
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    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);
*/

一一一一一一一一分割线一一一一一一一一

利用链表设计:

链表的实现就比较简单,但是此题有两个坑点

  • 给的是匿名结构体
  • 将链表链接起来比较的繁琐

思路:

在用数组实现时,我们定义了一头一尾两个下标,就可以判断长短

我们在链表实现时也要定义头尾指针来进行判断

但由于是匿名结构体

我们当前按下图这样的方式定义,当然定义方式会随着你的改变而改变

下图这样的方式定义意味着你的空间是这样的

c 复制代码
typedef struct List
{
    struct List* front;
    struct List* back;
    struct List* next;
    int val;
}List;

typedef struct {
    List* cq;
} MyCircularQueue;


插入或者删除时改变cq所指向的空间中front与back即可

front == back时为空,back->next == front时为满

代码实现:

注意: 结构体不能定义为ListNode,因为关于链表的题目一般会默认给你定义好一个这样的结构体,这也是博主经历后才知道的(痛苦)

c 复制代码
typedef struct List
{
    struct List* front;
    struct List* back;
    struct List* next;
    int val;
}List;

typedef struct {
    List* cq;
} MyCircularQueue;

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

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return obj->cq->back->next == obj->cq->front;
}

MyCircularQueue* myCircularQueueCreate(int k) {

    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->cq = NULL;

    List* cur = NULL;
    int tmp = k + 1;
    while (tmp--)
    {
        if (obj->cq == NULL)
        {
            obj->cq = (List*)malloc(sizeof(List));
            obj->cq->front = obj->cq->back = obj->cq->next = obj->cq;
            cur = obj->cq;
        }
        else
        {
            cur->next = (List*)malloc(sizeof(List));
            cur = cur->next;
        }
    }
    if (cur == NULL)
    {
        return obj;
    }
    cur->next = obj->cq;
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if (myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->cq->back->val = value;
    obj->cq->back = obj->cq->back->next;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->cq->front = obj->cq->front->next;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->cq->front->val;
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    List* cur = obj->cq->front;
    while (cur->next != obj->cq->back)
    {
        cur = cur->next;
    }
    return cur->val;
}



void myCircularQueueFree(MyCircularQueue* obj) {

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

有问题可以及时与博主交流,25小时高强度在线

相关推荐
Fan_web1 分钟前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
龙图:会赢的4 分钟前
[C语言]--编译和链接
c语言·开发语言
sp_fyf_202410 分钟前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
小字节,大梦想1 小时前
【C++】二叉搜索树
数据结构·c++
XKSYA(小巢校长)2 小时前
NatGo我的世界联机篇
开发语言·php
Cons.W2 小时前
Codeforces Round 975 (Div. 1) C. Tree Pruning
c语言·开发语言·剪枝
我是哈哈hh2 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
憧憬成为原神糕手2 小时前
c++_ 多态
开发语言·c++
VBA63372 小时前
VBA信息获取与处理第三个专题第三节:工作薄在空闲后自动关闭
开发语言
Tisfy2 小时前
LeetCode 2187.完成旅途的最少时间:二分查找
算法·leetcode·二分查找·题解·二分