Design a circular queue (the diagram is super detailed)

introduction

When we used the queue, we found that it was actually a little flawed. That is, after removing elements from the front of the queue, this space is released. If you want to insert elements again, you need to open up space again. In fact, this process has a certain impact on efficiency.

So there is the idea of ​​a circular queue:
a circular queue is a linear data structure, its operation performance is based on the FIFO (first in first out) principle and the tail of the queue is connected after the head of the queue to form a loop. It is also known as a "ring buffer".
One benefit of circular queues is that we can utilize previously used space on this queue. In a normal queue, once a queue is full, we cannot insert the next element, even if there is still room at the front of the queue. But with a circular queue, we can use this space to store new values.

This question requires us to implement an interface for a circular queue:
Designing a circular queue OJ link

design circular queue

topic introduction

insert image description here
We need to implement the following interface of the circular queue:

MyCircularQueue(k): Constructor, set the queue length to k;
Front: Get elements from the head of the queue. If the queue is empty, return -1;
Rear: Get the element at the end of the queue. If the queue is empty, return -1;
enQueue(value): Insert an element into the circular queue. Returns true if successful insertion;
deQueue(): removes an element from the circular queue. Returns true if deleted successfully;
isEmpty(): checks whether the circular queue is empty;
isFull(): checks whether the circular queue is full.

Brief description of ideas

For the circular queue, because the array can access the elements in the array at will, and the number of elements stored in the array can be easily calculated by the subscript. So we use arrays to implement this circular queue.
For a circular queue implemented by an array, we can store the subscripts of the queue head and queue tail elements for easy calculation.

But it is not difficult to find that when the queue is empty or the queue is full, the first and last subscripts are coincident, which makes us judge that there is a problem. So we can open up an additional space for an element, and this space will always be empty. When the tail subscript is one position ahead of the head subscript, it means that the circular queue is full;

Another problem is how to make the circular queue circulate.
If we just insert the tail subscript ++; after deletion, the head subscript –. Then the opened array is always full, and space reuse cannot be realized. We can actually put ++ or – after the subscript % length of the array. In this way, if the subscript ++ at the last position of the array and then % the length of the array is 0, it returns to the beginning of the array, thus realizing the logical loop of the array:

insert image description here

accomplish

We need a structure to store the array used to store data, the first and last subscripts, and the queue capacity:

typedef struct 
{
    
    
	int* data;//存储数据的数组
	int front;//队列首下标
	int rear;//队列尾下标
	int capacity;//队列容量
} MyCircularQueue;

Initialize the circular queue

When initializing the circular queue:
first dynamically open up a space for the structure of the storage queue;
then open up a space for the array of stored data. Since this space needs to contain an empty element, the size of the space is the size of the circular queue + 1 ;

Then initialize the capacity of the circular queue to k;
initialize the head subscript ftont and the tail subscript rear to 0;

Finally return the structure:
insert image description here

//初始化循环队列
MyCircularQueue* myCircularQueueCreate(int k) 
{
    
    
	MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
	assert(obj);
	obj->data = (int*)malloc(sizeof(int) * (k + 1));
	assert(obj->data);
	obj->capacity = k;
	obj->front = 0 % (obj->capacity + 1);
	obj->rear = 0 % (obj->capacity + 1);
	return obj;
}

Check if the circular queue is empty

It has been introduced before: when the front is the same as the rear, it means that the circular queue is empty, and it returns true at this time, otherwise it returns false:

//判断循环队列是否为空,为空返回真
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
    
    
	assert(obj);
	if (obj->front == obj->rear)//front与rear重合时循环队列为空
	{
    
    
		return true;
	}
	else
	{
    
    
		return false;
	}
}

Check if the circular queue is full

When judging whether it is full:
when the circular queue is full, rear must be at the previous position of front, that is, front-rear is 1; however, when front is 0, the value of front-rear is the value of negative capacity. We just need to include this case when judging:
insert image description here

//判断循环队列是否已满,已满返回真
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
    
    
	assert(obj);
	if (obj->front - obj->rear == 1 || obj->front - obj->rear == -(obj->capacity))//当rear在front前面一个时循环队列已满;当front为0时,rear为k才是已满
	{
    
    
		return true;
	}
	else
	{
    
    
		return false;
	}
}

from the circular queue

When the circular queue is tailed, the myCircularQueueIsFull function is first reused to determine whether the circular queue is full.
If it is not full, put an element in the position where the subscript of the circular queue is rear (the starting subscript of rear is 0, which actually points to the subscript of the next position of the tail element); then add rear+1% of the array
length The result of assigning to rear:
insert image description here

//从循环队列尾插入一个元素,成功返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    
    
	assert(obj);
	if (myCircularQueueIsFull(obj) == 0)//为真说明没有满
	{
    
    
		obj->data[obj->rear] = value;
		obj->rear = (obj->rear + 1) % (obj->capacity + 1);
		return true;

	}
	else
	{
    
    
		return false;
	}
}

from the head of the circular queue

When leaving the circular queue, first reuse the myCircularQueueIsEmpty function to determine whether the circular queue is empty;
then delete the element with the subscript front in the array: the so-called deletion means that the front can be moved backward by one element: so we will front+1 The result of % array length can be assigned to front:
insert image description here

//从循环队列头出一个元素,成功返回真
bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    
    
	assert(obj);
	if (myCircularQueueIsEmpty(obj) == 0)//为真说明不是空的
	{
    
    
		obj->front = (obj->front + 1) % (obj->capacity + 1);
		return true;
	}
	else
	{
    
    
		return false;
	}
}

Access the element at the head of the circular queue

When accessing the elements at the head of the queue, you only need to return the element whose subscript is front:

//访问队列头的元素,为空返回-1
int myCircularQueueFront(MyCircularQueue* obj) 
{
    
    
	assert(obj);
	if (myCircularQueueIsEmpty(obj) == 0)//为真说明不是空的
	{
    
    
		return obj->data[obj->front];
	}
	else
	{
    
    
		return EOF;
	}
}

Access the element at the tail of the circular queue

When accessing the elements at the end of the queue, you only need to return the element whose subscript is rear-1:

//访问队列尾的元素,为空返回-1
int myCircularQueueRear(MyCircularQueue* obj) 
{
    
    
	assert(obj); 
	if (myCircularQueueIsEmpty(obj) == 0)//为真说明不是空的
	{
    
    
        int n = 0;
        if(obj->rear==0)
        {
    
    
            n=obj->capacity;
        }
        else
        {
    
    
            n=obj->rear-1;
        }
		return obj->data[n];
	}
	else
	{
    
    
		return EOF;
	}
}

destroy circular queue

When destroying the circular queue, free the array storing the data, and then free the structure:

//销毁循环队列
void myCircularQueueFree(MyCircularQueue* obj) 
{
    
    
	obj->capacity = 0;
	free(obj->data);
	obj->front = 0;
	obj->rear = 0;
	free(obj);
}

Summarize

At this point, the topic and introduction of the circular queue are over

If you think that I did not introduce a certain part clearly or that there is a problem with a certain part, you are welcome to raise it in the comment area

If this article is helpful to you, I hope it will be connected with one click

Hope to make progress together with you

Guess you like

Origin blog.csdn.net/weixin_73450183/article/details/129769757