leetcode刷题——设计循环链表

题目要求我们设计循环队列,其特点是容量固定,队列循环,如图所示:

这里的队列我们以链表队列举例,对于循环,只需要把尾节点的指针指向头节点。重点是队列的容量固定:如何确定队列是否已满和空,我们可能第一时间想到的是普通队列的尾指针因为扩容导致的移动,即下面的图片:当队尾节点的next指针指向的是队头指针的时候说明是容量已满状态

即:Queue->tail->next == Queue->head;

但是这么做会有问题,就是当只有一个元素的时候(k=1),这时队列头尾指针都指向这一个节点,所以无论是否存储,队尾节点的next指针都指向队头,还有,当出队列一直出到最后一个节点,这时也无法判断是否为空,因为这时 Queue->tail == Queue->head存在,空和有一个节点,判断条件都不会变化。

那我们就来解决无法判断空当 k=1 一个节点时无法判断是否为满的情况,让判断条件在不同情况有差异:

首先是区分判断空的两种情况,按照出队列的规律,剩一个数据和空的区别就是队头指针向后移动一个单位,(因为循环队头指针相当于循环了一圈)所以可以说当Queue->tail->next == Queue->head 的时候为空,这正好也是容量满的条件,为了区分这两种情况,我们可以新增一个节点(总共 k+1 个节点)不存储有效数据,区分这两种情况:

即Queue->tail->next == Queue->head 时说明容量已经满,
Queue->tail->next->next == Queue->head 时说明空。

第一张图片是已经满的情况,第二张图片是一直出队列直到为空的情况,分别对应两种情况,新增节点同样可以解决 k=1 的情况。

通俗的来解释就是新增了一个节点,当队尾节点两次next后才找到队头节点说明容量满了,当队尾节点一次next后就找到队头节点就说明(队头节点一直出队列甚至把队尾节点出掉)队列空了。

接下来是代码部分,首先是创建循环队列:

cpp 复制代码
struct QueueNode {
    int val;
    struct QueueNode* next;
};

typedef struct {
    struct QueueNode* head;
    struct QueueNode* tail;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    int count = k;
    struct QueueNode* cur_next = NULL;
    q->head = (struct QueueNode*)malloc(sizeof(struct QueueNode));
    struct QueueNode* cur = q->head;
    for (count; count > 0; count--) {
        cur_next = (struct QueueNode*)malloc(sizeof(struct QueueNode));
        cur->next = cur_next;
        cur = cur_next;
    }if (cur_next != NULL) {
        q->tail = cur_next;
        cur_next->next = q->head;
    }
    return q;
}

注意creat函数创建了 k+1 个节点,并且队头队尾指针指向同一节点。

接着是判断容量满和空的函数:

cpp 复制代码
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if (obj->tail->next == obj->head) {
        return true;
    }
    else {
        return false;
    }
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if (obj->tail->next->next == obj->head) {
        return true;
    }
    else {
        return false;
    }
}

和刚才解释的条件一样。

然后是检查是否插入或删除成功的函数:

cpp 复制代码
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if (myCircularQueueIsFull(obj)) {
        return false;
    }
    obj->tail = obj->tail->next;
    obj->tail->val = value;
    return true;
}

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

这里删除函数我是直接把队头指针向后next操作一下。

最后是返回队头函数和返回队尾元素函数:

cpp 复制代码
int myCircularQueueFront(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj)) {
        return -1;
    }
    return obj->head->val;
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj)) {
        return -1;
    }
    return obj->tail->val;
}

直接返回即可。

最后不要忘记写free函数,这就是文章的全部内容了,解释的很烂还请谅解,如有错误欢迎指出。

相关推荐
滴滴答滴答答29 分钟前
LeetCode Hot100 之 16 合并两个有序链表
算法·leetcode·链表
ASKED_20191 小时前
企业级大模型微调(Fine-tuning)策略
大数据·人工智能·算法
圣保罗的大教堂1 小时前
leetcode 3713. 最长的平衡子串 I 中等
leetcode
t198751281 小时前
基于Chirp分解和多相快速算法的离散分数傅里叶变换(DFRFT)MATLAB实现
开发语言·算法·matlab
愚者游世1 小时前
力扣解决二进制 | 题型常用知识点梳理
c++·程序人生·算法·leetcode·职场和发展
阿星AI工作室2 小时前
宝藏skills!90个顶尖博客信源自动抓,AI每天帮我筛出20篇精华!
人工智能·算法
程序员酥皮蛋2 小时前
hot 100 第二十四题 24.回文链表
数据结构·链表
Ulyanov2 小时前
基于Python的单脉冲雷达导引头回波生成技术
python·算法·仿真·单脉冲雷达、
ersaijun2 小时前
机器人动力学库Pinocchio、RBDL 和 KDL区别
算法·机器人·控制·开源库
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章25-ORB特征点
图像处理·人工智能·opencv·算法·计算机视觉