1、确定使用链表还是数组
一看到循环,大家应该很容易想到循环链表,但是循环链表在此题中没有很大优势,我们优先选择数组。原因如下:
判断何时为空和何时为满的情况(假设k=4)
i.front==rear为空,rear指向尾节点的下一个节点位置。
但是会发现,当插入第四个数时,rear会又回到和front一样的位置上,这样就很难判断何时未满和空的情况。此时可以定义一个size,当size==0时为空,size==k为满,但这样给我们写代码加了很多难度,不建议。
再说找尾,找头很好找,但是找尾需要知道rear的上一个节点,那这样循环链表要变为双向循环链表,很麻烦。
ii.front==rear为空,rear指向尾节点。
这样的确很好找头和尾,但是在删除最后一个数据的情况要特殊处理,也很麻烦。
iii.front指向头结点,rear==NULL为空。
这样当插入第一个数时,rear指向尾节点。但在删除数据的时候,删除第一个,front指向下一个。到最后一个数据,需要对rear进行单独处理。
综上,我们使用数组进行处理。
2.建立数组框架
我们在建立数组的时候,多建立一个。就比如k=4,我们建立数组的长度为5。多开一个空间解决假溢出问题。
3.判断何时为空、何时为满
3.1为空
rear==front为空,rear指向尾节点的下一个节点。
3.2为满
3.2.1第一种情况
rear+1==front为满
3.2.2第二种情况
这种情况就不能用rear+1==front来判断了。可以这样:(rear+1)%(k+1)== front来判断就可以了。这个式子也适用于第一种情况。
4.获取首元素
这个很好获取,front指向的就是首元素。
5.获取尾元素
5.1第一种情况
rear指向尾节点下一个元素,那获取尾元素需要rear-1。
5.2第二种情况
这种情况肯定不能直接rear-1,用(rear-1+k+1)可以处理。
但是第一种情况不适用,那我们再%(k+1)。即(rear-1+k+1)%(k+1)。
6.加入数据和删除数据
6.1加入数据
加入第四个元素时,rear不能直接+1,需要(rear+1)%(k+1),加入数据。
6.2删除数据
删除数据,我们直接front往后移动就行。
这种情况想要删除数据,不能直接front+1,需要(front+1)%(k+1)。
代码如下:
typedef struct {
int *a;
int front;
int rear;
int k;
} MyCircularQueue;//使用数组
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* Queue=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//malloc一个MyCircularQueue结构体
Queue->a=(int*)malloc(sizeof(int)*(k+1));//malloc一个数组
Queue->front=Queue->rear=0;
Queue->k=k;
return Queue;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front==obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
if((obj->rear+1)%(obj->k+1)==obj->front)return true;
return false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))return false;
obj->a[obj->rear]=value;
obj->rear++;
obj->rear =(obj->rear)%(obj->k+1);//这两步也可以合成obj->rear = (obj->rear+1)%(obj->k+1)
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))return false;
obj->front++;
obj->front =(obj->front)%(obj->k+1);//循环数组所以用模处理预防超出
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))return -1;
return obj->a[(obj->rear-1+obj->k+1)%(obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);//释放的话先释放obj->a
obj->a=NULL;
free(obj);//再释放obj
obj=NULL;
}
谢谢你看到这里哟!
over~