Circular queue
I. Overview
Because of the special structure of the queue, we generally use chained lists as in the previous section. But sometimes, the sequence structure has the advantage of the sequence structure, so we can also use the sequence table to implement the list in some way. That is achieved through circular queues.
2. Principle realization
1. Node
Because it is a sequential structure, our node does not need other things, only needs to store data.
2. Circular queue structure
Because of the special mechanism of the circular queue, we generally do not consider expanding the queue. Then it should have a fixed length MaxSize
. Because a queue which consists of three parts 基址*base
, front头指针
, tail尾指针
. Because it is a loop, the value of our tail pointer may be in front of the head pointer. For example MaxSize=6 front=4 tail=2
, our queue length should be 4 5 0 1
these 4 positions, so if we calculate it, it should be (tail-front+MaxSize)%Maxsize
.
3. Queue initialization and empty queue judgment
The queue is initialized, *base
the storage space is directly generated dynamically , and then the storage space is generated front=tail=0
. If it is an empty queue, then because of it front=tail
.
4. Judgment that the queue is full
Our queue is full, there are two cases, before the end of the first: tail=MaxSize-1
, ; front=0
there is a function of case is before the end of the first: tail+1=front
. So, to sum up, its judgment should be (tail+1)%MaxSize=front
.
5. Enrollment of the queue
To join the team, we only need to tail
write the place we inserted the value, and then ++tail
there may be tail+1=MaxSize
situations, so we need to use one if
or 计算
to modify its value. Personally recommend using calculations tail = (tail+1)%MaxSize
. But in theory, using if to update will not go wrong. But sometimes, we may use 快慢指针
the method to do some problems, so the fault tolerance rate of this method of calculation may be much better.
But note that if we first judge whether the queue is full, the maximum number of stored elements in the queue will be Maxsize-1
, because tail
it is always 尾元
the location, it is directly available, and the judgment is full tail+1=front
, so the last element is useless. Unless we modify the way of judging that the team is full, as shown in the figure below, J8 is actually the above because there should be no data:
6. Dequeue
Dequeue is similar to enqueue, but we don't need to do anything with the address in order structure, we only need to put the head pointer front+1
. Of course, there are also MaxSize
cases of exceeding , so we still have to adopt some fault tolerance mechanisms:front = (front+1)%MaxSize
Three. Code implementation
#include <stdio.h>
#include <stdlib.h>
#define ERROR 0
#define OK 1
#define OverFlow 2
#define MaxSize 5
typedef struct dataType{
int data;
}dataType;
typedef struct cqueue{
dataType *base;
int front;
int tail;
}cqueue;
cqueue* CqueueInit(void);
int CqueuePush(cqueue* q, dataType data);
int CqueueGet(cqueue *q, dataType *data);
int CqueuePop(cqueue *q);
int CqueueShow(cqueue *q);
int main()
{
// 主函数随便改
cqueue *q = CqueueInit();
dataType test;
test.data = 0;
CqueuePush(q,test);
test.data = 1;
CqueuePush(q,test);
test.data = 2;
CqueuePush(q,test);
test.data = 3;
CqueuePush(q,test);
CqueuePop(q);
test.data = 4;
CqueuePush(q,test);
CqueueShow(q);
return 0;
}
cqueue* CqueueInit(void)
{
cqueue *q = (cqueue*)malloc(sizeof(cqueue));
dataType *data = (dataType*)malloc(sizeof(dataType)*MaxSize);
if (q != NULL && data != NULL)
{
q->base = data;
q->front = 0;
q->tail = 0; // 初始化循环队列
return q;
}
exit(0);
}
int CqueuePush(cqueue* q, dataType data)
{
if ((q->tail+1)%MaxSize == q->front) return OverFlow;
// 注意这样的写法会导致最后有一个节点存不到数据
*(q->base+q->tail) = data;
q->tail += 1;
return OK;
}
int CqueueGet(cqueue *q, dataType *data)
{
if ((q->tail - q->front)%MaxSize == 0)
{
return ERROR;
}
else
{
*data = *(q->base+q->tail); // 返回头指针指向的值
return OK;
}
}
int CqueuePop(cqueue *q)
{
q->front += 1; // 更新一下指向的元素
return OK;
}
int CqueueShow(cqueue *q) // 这个函数就打印一下队列 看看效果
{
int start,end = 0;
int cont = 0;
if (q->tail < q->front) // 队尾在队头的前面
{
end = q->tail + MaxSize;
}
else
{
end = q->tail; // 队头在队尾的前面
}
for(start = q->front; start < end; ++start)
{
printf("No.%d data is %d\n", cont, (q->base+start)->data);
++cont;
}
}