[Registro de aprendizaje de estructura de datos 9] -cola de dos vías

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 1estas 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, *baseel 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.
Inserte la descripción de la imagen aquí

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=0no 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 tailescribir el lugar donde insertamos el valor, y luego ++tailpuede haber tail+1=MaxSizesituaciones, por lo que debemos usar uno ifo 计算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 tailsiempre 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:
Inserte la descripción de la imagen aquí

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 MaxSizecasos 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;
    }
}

Supongo que te gusta

Origin blog.csdn.net/u011017694/article/details/109459539
Recomendado
Clasificación