【leetcode】622. 设计循环队列(Circular Queue)

文章目录

  • 1. 怎么设计循环队列?
  • 2. 数组实现循环队列

往期相关文章推荐:
1.队列(Queue)
2.栈(Stack)之浅谈数组和链表实现栈各自的优缺点
3.线性表之链表(Linked List)
4.线性表之顺序表(Sequence List)

1. 怎么设计循环队列?

  循环队列也叫环形队列,可以用数组或循环链表实现,使用场景是在那种只需要固定空间大小,且一直有插入删除的情况。设计循环队列最大的问题是怎么确定队列是空还是满的状态,如果是增加额外变量size记录数据个数,则很容易解决这个问题,不过这里不打算使用size的方式。

下面将一步步分析使用数组的方式如何实现,至于循环链表实现队列,看似天然循环,实际还是很多大坑等着,有些问题处理起来比较坑人,只有双向循环链表实现起来比较轻松,单向循环链表实现循环队列得被坑死。

先以数组来看,判空很简单,front == rear那就是空;如何判满是比较困难的,可不敢简单认为rear == length - 1就完了,环形队列满了后,rear自然要绕回rear = 0,这样才符合环形队列的设计,可这样就无法区分满队列的状态了。
【leetcode】622. 设计循环队列(Circular Queue)_第1张图片

直接这么设计就能解决了:给数组多开1个大小,这是多出来的,不存储数据,为的就是隔开队头和队尾
【leetcode】622. 设计循环队列(Circular Queue)_第2张图片

即使是下面这种情况也能解决:
【leetcode】622. 设计循环队列(Circular Queue)_第3张图片
这样判断队列空的条件还是front == rear,判断队列满则是(rear + 1) % length == front。还有一个问题就是,在插入或删除完数据后,要是rear或front == length,则需要将rear或front重新置0,也就是绕回去。如上图显示,rear = 5,当需要再次插入数据,5下标位置放入60后,rear = 6了,总不能在6下标位置开始放,所以这时插入数据后需要置0。在删除数据时也是同理,front一直++,总会来到==length的时刻,同样需要置0。

2. 数组实现循环队列

设计循环队列 leetcode题目链接
【leetcode】622. 设计循环队列(Circular Queue)_第4张图片

typedef struct {
    int* arr;
    int front;
    int rear;
    int lgth;
} MyCircularQueue;

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

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

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* queue = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    queue->arr = (int*)calloc(k + 1, sizeof(int));
    queue->lgth = k + 1;
    queue->front = queue->rear = 0;
    return queue;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if (myCircularQueueIsFull(obj)) {
        return false; 
    }
    obj->arr[obj->rear++] = value;

    // 绕回去 obj->rear %= obj->lgth; 
    if (obj->rear >= obj->lgth) {
        obj->rear = 0; 
    } 
    return true; 
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj)) {
        return false;
    }
    obj->arr[obj->front++] = 0;

    // 绕回去 obj->front %= obj->lgth;
    if (obj->front >= obj->lgth) {
        obj->front = 0; 
    } 
    return true;
}

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

int myCircularQueueRear(MyCircularQueue* obj) {
    if (myCircularQueueIsEmpty(obj)) {
        return -1;
    }
    // 特殊处理
    return obj->rear == 0 ? obj->arr[obj->lgth - 1] : obj->arr[obj->rear - 1];
    // 或者 return obj->arr[(obj->rear - 1 + obj->lgth) % obj->lgth];
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    obj->arr = NULL;
    obj->front = obj->rear = obj->lgth = 0;
}

计算循环队列数据个数:(rear + lgth - front) % leth。

你可能感兴趣的:(Data,Structure,and,Algorithm,C语言,刷题,leetcode,c语言,数据结构,算法)