Cola circular
I. Panorama general
Debido a la estructura especial de la cola, generalmente usamos listas encadenadas como en la sección anterior. Pero a veces, la estructura de secuencia tiene la ventaja de la estructura de secuencia, por lo que también podemos usar la tabla de secuencia para implementar la lista de alguna manera. Eso se logra mediante colas circulares.
2. Realización de principios
1. Nodo
Debido a que es una estructura secuencial, nuestro nodo no necesita otras cosas, solo necesita almacenar datos.
2. Estructura de cola circular
Debido al mecanismo especial de la cola circular, generalmente no consideramos expandir la cola. Entonces debería tener una longitud fija MaxSize
. Debido a una cola que consta de tres partes 基址*base
, front头指针
, tail尾指针
. Debido a que es un bucle, el valor de nuestro puntero de cola puede estar delante del puntero de cabeza. Por ejemplo MaxSize=6 front=4 tail=2
, la longitud de nuestra cola debería ser 4 5 0 1
estas 4 posiciones, así que si la calculamos, debería ser (tail-front+MaxSize)%Maxsize
.
3. Inicialización de la cola y juicio de la cola vacía
La cola se inicializa, *base
el espacio de almacenamiento se genera directamente de forma dinámica y luego se genera el espacio de almacenamiento front=tail=0
. Si es una cola vacía, entonces por eso front=tail
.
4. Sentencia de que la cola está llena
Nuestra cola está llena, hay dos casos, antes del final de la primera: tail=MaxSize-1
,; front=0
no es una función del caso está antes del final de la primera: tail+1=front
. Entonces, para resumir, su juicio debería ser (tail+1)%MaxSize=front
.
5. Inscripción de la cola
Para unirnos al equipo, solo necesitamos tail
escribir el lugar donde insertamos el valor, y luego ++tail
puede haber tail+1=MaxSize
situaciones, por lo que debemos usar uno if
o 计算
modificar su valor. Recomiendo personalmente el uso de cálculos tail = (tail+1)%MaxSize
. Pero en teoría, usar if para actualizar no saldrá mal. Pero a veces, podemos usar 快慢指针
el método para solucionar algunos problemas, por lo que la tasa de tolerancia a fallas de este método de cálculo puede ser mucho mejor.
Pero tenga en cuenta que si primero juzgamos si la cola está llena, el número máximo de elementos almacenados en la cola será Maxsize-1
, porque tail
siempre es 尾元
la posición, está directamente disponible y el juicio está lleno tail+1=front
, por lo que el último elemento no se puede usar . A menos que modifiquemos la forma de juzgar que el equipo está completo, como se muestra en la figura siguiente, J8 se debe en realidad a que no debería haber datos:
6. Retirar de la cola
Dequeue es similar a enqueue, pero no necesitamos hacer nada con la dirección en la estructura de orden, solo necesitamos poner el puntero de cabeza front+1
. Por supuesto, también hay MaxSize
casos de superación , por lo que aún tenemos que adoptar algunos mecanismos de tolerancia a fallos:front = (front+1)%MaxSize
Tres. Implementación del código
#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;
}
}