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

相关推荐
penguin_bark4 分钟前
69. x 的平方根
算法
这可就有点麻烦了14 分钟前
强化学习笔记之【TD3算法】
linux·笔记·算法·机器学习
苏宸啊19 分钟前
顺序表及其代码实现
数据结构·算法
lin zaixi()23 分钟前
贪心思想之——最大子段和问题
数据结构·算法
FindYou.23 分钟前
C - Separated Lunch
算法·深度优先
夜雨翦春韭29 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
Kent_J_Truman40 分钟前
【平方差 / C】
算法
一直学习永不止步41 分钟前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序
Amor风信子1 小时前
华为OD机试真题---跳房子II
java·数据结构·算法
戊子仲秋1 小时前
【LeetCode】每日一题 2024_10_2 准时到达的列车最小时速(二分答案)
算法·leetcode·职场和发展