[Data structure learning record 9]-two-way 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 1these 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, *basethe 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.
Insert picture description here

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=0there 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 tailwrite the place we inserted the value, and then ++tailthere may be tail+1=MaxSizesituations, so we need to use one ifor 计算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 tailit 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:
Insert picture description here

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

Guess you like

Origin blog.csdn.net/u011017694/article/details/109459539