Of hand tearing data structure -- queue

catalogue

Concept and structure of queue

Implementation of queue

Array queue

Chain queue

Implementation of chain queue

Initialize queue

Queue

Out of queue

Get queue header element

Get queue tail element

Gets the number of valid elements in the queue

Check whether the queue is empty

Destroy queue

Implement all the code of the queue

test case

Concept and structure of queue

Queue: a special linear table that only allows inserting data at one end and deleting data at the other end. The queue has a first in first out FIFO(First In First Out).

Enter queue: the end of the queue at which the insertion operation is performed is called the end of the queue.

Out of queue: the end for deletion is called the queue head.

Implementation of queue

There are two ways to implement queue: 1. Using array and 2. Using linked list.

Array queue

Disadvantages: when the element is out of the queue, it needs to move the subsequent data to the front, which is inefficient.

Chain queue

Save two pointers to the head and tail of the team in the queue. When leaving the team, just point the pointer to the head of the team to the next of the original head, and enter directly behind the tail of the team when entering the team

Therefore, using the structure of linked list will be better.

Implementation of chain queue

First create the structure of a single element in the queue, and then create a queue structure, including two pointers to the head and tail.

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;

The interfaces to be implemented are given below:

//Initialize queue
void QueueInit(Queue* pq);

//Queue
void QueuePush(Queue* pq, QDataType x);
//Out of queue
void QueuePop(Queue* pq);

//Get queue header element
QDataType QueueFront(Queue* pq);
//Get queue tail element
QDataType QueueBack(Queue* pq);

//Gets the number of valid elements in the queue
int QueueSize(Queue* pq);

//Check whether the queue is empty. If it is empty, it returns a non-zero result. If it is not empty, it returns 0
bool QueueEmpty(Queue* pq);

//Destroy queue
void QueueDestroy(Queue* pq);

Initialize queue

The queue initialization only needs to point to null two pointers pointing to the head and tail.

void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = pq->tail = NULL;
}

Queue

First, apply for space to create the element. If there is no element in the queue, take the element as the head and tail of the queue; If there is an element in the queue, connect the element directly to the end of the queue and point the end pointer of the queue to the element.

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (newNode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	newNode->data = x;
	newNode->next = NULL;

	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newNode;
	}
	else
	{
		pq->tail->next = newNode;
		pq->tail = newNode;
	}
}

Out of queue

When leaving the queue, first check whether there are elements in the queue. If there are no elements in the queue, let the program directly report an error.

Elements can be divided into one or more elements:

One element: directly release the node and point to null the head and tail pointers in the original queue.

Multiple elements: first save the header pointer to the next node of the node, then release the header node and point the header pointer to the original saved value.

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head);//If the queue is empty, no element can be out of the queue and an error is reported directly

	//1. One element
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
    //2. Multiple elements
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

Get queue header element

When obtaining elements, first check whether there are elements in the queue. If there are no elements, an error will be reported directly. If there are elements, the data with the header pointer pointing to the node will be returned.

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);

	return pq->head->data;
}

Get queue tail element

Similar to getting the team header element.

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);

	return pq->tail->data;
}

Gets the number of valid elements in the queue

Start from the head of the queue to traverse the whole queue and count. During traversal, a new variable should be created for traversal to ensure that the head pointer is not changed.

int QueueSize(Queue* pq)
{
	assert(pq);

	int size = 0;
	QNode* cur = pq->head;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

Check whether the queue is empty

Returns a non-zero result if it is empty and 0 if it is not empty

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

Destroy queue

Each element in the queue is a newly opened node, so it needs to be destroyed one by one. After all nodes are destroyed, point the head and tail pointers to null.

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
}

Implement all the code of the queue

#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>

typedef int QDataType;

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;

//Initialize queue
void QueueInit(Queue* pq);

//Team tail in
void QueuePush(Queue* pq, QDataType x);
//Team leader
void QueuePop(Queue* pq);

//Get queue header element
QDataType QueueFront(Queue* pq);
//Get queue tail element
QDataType QueueBack(Queue* pq);

//Gets the number of valid elements in the queue
int QueueSize(Queue* pq);

//Check whether the queue is empty. If it is empty, it returns a non-zero result. If it is not empty, it returns 0
bool QueueEmpty(Queue* pq);

//Destroy queue
void QueueDestroy(Queue* pq);

void QueueInit(Queue* pq)
{
	assert(pq);

	pq->head = pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newNode = (QNode*)malloc(sizeof(QNode));
	if (newNode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	newNode->data = x;
	newNode->next = NULL;

	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newNode;
	}
	else
	{
		pq->tail->next = newNode;
		pq->tail = newNode;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head);

	//1. One
	//2. Multiple
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);

	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);

	return pq->tail->data;
}

int QueueSize(Queue* pq)
{
	assert(pq);

	int size = 0;
	QNode* cur = pq->head;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->head == NULL;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->head = pq->tail = NULL;
}

test case

void TestQueue()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
    printf("%d ", QueueBack(&q));

	QueuePop(&q);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);
	printf("%d ", QueueFront(&q));

	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);

    printf("QueueSize:%d\n", QueueSize(&q));

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");

	QueueDestroy(&q);
}

int main()
{
    TestQueue();
    return 0;
}

 

Keywords: data structure linked list queue

Added by anauj0101 on Sat, 30 Oct 2021 06:42:51 +0300