设计循环队列(OJ)

 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
    • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

一.思路和分析

 要求实现一个固定容量的循环队列,我们主要要思考一下问题

1.如何判断队空

2.如何判断队满

3.如何循环存放数据

        如果使用单链表储存,那么数据访问比较麻烦,如果设定队尾指针指向队尾的下一个数据,用队头和队尾相等来判断队空,那么队满就不好判断,要么再引进一个size,要么就记录队尾的前一个,这些方法比较麻烦,如果设定队尾指向队尾元素,队尾和队头为空即队空,那么队满也是一个难题,

所以我们不妨使用数组来实现队列,我们设定队尾指针指向队尾的下一个

方法一:使用size计数,size为0即为空,size与队容量相等即为满,使用余数计算存放位置

方法二:多开一个空间,比如要求5个空间,我们开6个空间,那么队头等于队尾即为空,队头的上一个为队尾即为满,使用余数计算存放位置

设计循环队列(OJ)_第1张图片

二.方法一

分部代码

1.结构

typedef struct {
    int *arr;
    int front;
    int back;
    int size;
    int k;
} MyCircularQueue;

我们使用一个size计数,arr为队列,front为队头,back为队尾,k为容量

2.初始化

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* q=( MyCircularQueue*)malloc(sizeof( MyCircularQueue));
    q->arr=(int*)malloc(sizeof(int)*k);
    q->front=0;
    q->back=0;
    q->size=0;
    q->k=k;
    return q;
}

分配空间,初始化值

3.销毁

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

4.判断队空

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->size==0;
}

5.判断队满

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return obj->size==obj->k;
}

6.入队

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

如果队满即失败, obj->back%=obj->k,当队走到尾,如果队没有满,说明前面有空间,所以我们就取余数,让队尾循环到数组头,

7.出队

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->front++;
    obj->front%=obj->k;
    obj->size--;
    return true;
}

如果队空即失败,obj->front%=obj->k,当队头走到尾,如果队列不为空,说明前面有数据,就让头循环回到数据头

8.取队头元素

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

9.取队尾元素

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    int a=(obj->back+obj->k-1)%obj->k;
    return obj->arr[a];
}

在我们的设定中,队尾指向队尾的下一个,所以我们就会出现当队尾指针指向数组头时,队尾元素实际是在数组尾,使用(obj->back+obj->k-1)%obj->k来获取队尾,

完整代码




typedef struct {
    int *arr;
    int front;
    int back;
    int size;
    int k;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* q=( MyCircularQueue*)malloc(sizeof( MyCircularQueue));
    q->arr=(int*)malloc(sizeof(int)*k);
    q->front=0;
    q->back=0;
    q->size=0;
    q->k=k;
    return q;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->size==0;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return obj->size==obj->k;
}

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

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->front++;
    obj->front%=obj->k;
    obj->size--;
    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;
    int a=(obj->back+obj->k-1)%obj->k;
    return obj->arr[a];
}


void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

三.方法二

分部代码

1,结构

typedef struct {
    int *arr;
    int front;
    int back;
    int k;
} MyCircularQueue;

这个方法更多使用取模运算

2.初始化

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

为了方便取模运算判断队空和队满,我们多开一个空间

3.销毁

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

4.判断队空

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

在这里,我们规定头等于尾为空

5.判断队满

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->front-obj->back+obj->k)%(obj->k+1)==0;
}

我们规定尾等于头的上一个为满,所以我们让头减去尾再加上K,如果恰好为总容量+1,就为满,假设为满,那么头减去尾应该为1或-K,加上一个K即可判断

6,入队

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

尾指向尾数据的下一个,我们多开了一个空间,所以循环时应该模K+1

7.出队

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->front++;
    obj->front%=(obj->k+1);
    return true;
}

同上,不过是改变头

8.取队头元素

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

9.取队尾元素

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    int a=(obj->back+obj->k)%(obj->k+1);
    return obj->arr[a];
}

完整代码




typedef struct {
    int *arr;
    int front;
    int back;
    int k;
} MyCircularQueue;


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

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

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->front-obj->back+obj->k)%(obj->k+1)==0;
}

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

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->front++;
    obj->front%=(obj->k+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;
    int a=(obj->back+obj->k)%(obj->k+1);
    return obj->arr[a];
}


void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

你可能感兴趣的:(OJ,数据结构,算法,c语言,数据结构)