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函数,这就是文章的全部内容了,解释的很烂还请谅解,如有错误欢迎指出。

相关推荐
前端小L44 分钟前
动态规划的“数学之魂”:从DP推演到质因数分解——巧解「只有两个键的键盘」
算法·动态规划
RTC老炮1 小时前
webrtc弱网-ReceiveSideCongestionController类源码分析及算法原理
网络·算法·webrtc
21号 11 小时前
9.Redis 集群(重在理解)
数据库·redis·算法
码农多耕地呗2 小时前
力扣146.LRU缓存(哈希表缓存.映射+双向链表数据结构手搓.维护使用状况顺序)(java)
数据结构·leetcode·缓存
hadage2333 小时前
--- 数据结构 AVL树 ---
数据结构·算法
liu****3 小时前
8.list的使用
数据结构·c++·算法·list
阿拉丁的梦3 小时前
后期材质-屏幕冲击径向模糊
算法·材质
weixin_429630264 小时前
实验二-决策树-葡萄酒
算法·决策树·机器学习
茉莉玫瑰花茶4 小时前
floodfill 算法(dfs)
算法·深度优先
CoderCodingNo5 小时前
【GESP】C++五级考试大纲知识点梳理, (5) 算法复杂度估算(多项式、对数)
开发语言·c++·算法