# Sequential queue, cyclic queue, chain queue

Posted by pacholo on Sat, 04 Sep 2021 04:38:24 +0200

# preface

Queue is a "first in, first out" linear table. Only one end of the table is inserted (queued), which is called the end of the queue, and the other end is deleted (queued), which is called the opposite end, that is, "tail in, head out". Only the head and tail of the queue can be accessed by the outside world, so it cannot be traversed. All kinds of queues in life are queues.
There are two storage methods for queues: sequential storage and chain storage. The queue with sequential storage is called sequential queue, and the queue with chain storage is called chain queue.

# 1, Sequential queue

The sequential queue stores the elements in the queue in the form of array, and uses the head pointer (front) and tail pointer (rear) to point to the opposite head and tail of the queue respectively.

```/*----------------------------------------------------------------
Set up a team head pointer front and a team tail pointer rear to point to the team head and team tail elements respectively.

◆ Initialization: front=rear=0.
◆ The queue is empty: front==rear.
◆ Queue full: rear==MaxSize.
◆ Join the queue: insert the new element into the position indicated by the rear, and then add 1 to the rear.
◆ Out of line: delete the element indicated by front, then add 1 and return the deleted element.
◆ Take the first element of the queue: return the element value pointed to by the front
-----------------------------------------------------------------*/

#include <stdio.h>
#include <assert.h>
#include <Windows.h>

#define MaxSize 10 / / the maximum capacity of the queue

typedef int DataType;  //Element type in queue
typedef struct Queue
{
DataType Queue[MaxSize];
int rear;    //Tail pointer
}SeqQueue;

//Queue initialization: initializes the queue as an empty queue
void InitQueue(SeqQueue *SQ)
{
SQ->fornt = SQ->rear = 0;  //Set the head and tail pointers to 0 at the same time
}

//Judge that the queue is empty

int IsEmpty(SeqQueue* SQ)
{
if (SQ->fornt == SQ->rear)
{
return 1;
}
return 0;
}

//Determine whether the queue is full

int IsFull(SeqQueue* SQ)
{
if (SQ->rear == MaxSize)
{
return 1;
}
return 0;
}

//Join the queue and insert the element data into the queue SQ

void EnterQueue(SeqQueue* SQ,DataType data)
{
if (IsFull(SQ))
{
printf("The queue is full\n");
return 0;
}
SQ->Queue[SQ->rear] = data;  //Insert element data at the end of the queue
SQ->rear = SQ->rear + 1;     //The tail pointer moves back one bit
}

//Out of the queue, the element data of the queue head in the queue is out of the queue. After out of the queue, the queue head pointer front is moved back one bit
int DeleteQueue(SeqQueue* SQ,DataType* data)
{
if (IsEmpty(SQ))
{
printf("The queue is empty!\n");
return 0;
}
*data = SQ->Queue[SQ->fornt];   //Out of queue element value
SQ->fornt = (SQ->fornt)+1;      //The tail pointer moves back one bit
return 1;
}

{
if (IsEmpty(SQ))
{
printf("Queue is empty!\n");
}
return *data = SQ->Queue[SQ->fornt];
}

//Empty queue

void ClearQueue(SeqQueue* SQ)
{
SQ->fornt = SQ->rear = 0;
}

//And elements in the print queue

void PrintQueue(SeqQueue* SQ)
{
assert(SQ);
int i = SQ->fornt;
while(i<SQ->rear)
{
printf("%-3d", SQ->Queue[i]);
i++;
}
printf("\n");
}
int main()
{
SeqQueue SQ;
DataType data;
//Initialize queue
InitQueue(&SQ);
//Join the team
EnterQueue(&SQ, 1);
EnterQueue(&SQ, 2);
EnterQueue(&SQ, 3);
EnterQueue(&SQ, 4);
EnterQueue(&SQ, 5);
EnterQueue(&SQ, 6);
EnterQueue(&SQ, 8);
EnterQueue(&SQ, 10);
EnterQueue(&SQ, 12);
EnterQueue(&SQ, 15);
EnterQueue(&SQ, 16);

//Print elements in queue
printf("The elements in the queue are:");
PrintQueue(&SQ);
printf("\n");
//Out of the team
DeleteQueue(&SQ, &data);
printf("The outgoing elements are:%d\n", data);
printf("\n");
DeleteQueue(&SQ, &data);
printf("The outgoing elements are:%d\n", data);
printf("\n");
printf("The elements in the queue are:");
PrintQueue(&SQ);
printf("\n");
printf("The team head elements are:%d\n", data);
printf("#Element 16 join the team#\n");
//Element 16 join the team
EnterQueue(&SQ, 16);
printf("The elements in the queue are:");
PrintQueue(&SQ);
printf("\n");
system("pause");
return 0;
}
```

The result is:

It can be seen from the above that once the queue is full, even if there are elements out of the queue, the queue entry operation cannot be carried out because of the "false overflow" of the sequential queue. The appearance of false overflow is that the queue head will generate new space due to out of queue operation, but the queue tail pointer has reached the end of the array, and the queue tail pointer will cross the upper bound of the array, resulting in overflow. This overflow is not caused by insufficient storage space, but by multiple inserts and deletions. Such operations with storage space but unable to insert elements are called "false overflow". As shown in the figure below:

# 2, Circular queue

In order to make full use of the storage space and eliminate the "false overflow phenomenon", the space allocated by the queue can be regarded as a ring connected end to end. Such a queue is called a circular queue.
When the loop queue is empty or full, the head pointer and tail pointer point to the same position, that is, front = =rear; To distinguish between these two situations, you can:

1. Set a flag to distinguish the empty and full teams.
2. Set a counter to count the elements. If it is 0, it means the team is empty, and if it is equal to the team capacity, it means the team is full.
3. Use less one element space. The rear of the queue tail points to the last element of the actual queue tail.
Team empty: front == rear;
Team full: (rear + 1)% MaxSize = = front.

```/*----------------------------------------------------------------
Set up a team head pointer front and a team tail pointer rear to point to the team head and team tail elements respectively.

◆ Initialization: front=rear=0.
◆ The queue is empty: front==rear.
◆ Team full: (rear + 1)% maxsize = = font
◆ Join the queue: insert the new element into the position indicated by the rear, and then add 1 to the rear.
◆ Out of line: delete the element indicated by front, then add 1 and return the deleted element.
◆ Get the first element of the queue: return the element value pointed to by the font
-----------------------------------------------------------------*/

#include<stdio.h>
#include<Windows.h>
#include<assert.h>

#define MaxSize 10
typedef int DataType;
typedef struct SeqQueue
{
DataType Queue[MaxSize];
int fornt;
int rear;
}SeqCirQueue;

//Queue initialization

void InitSeqCirQueue(SeqCirQueue* SCQ)
{
SCQ->fornt = SCQ->rear = 0;
}

//Determine whether the queue is empty
int IsEmpty(SeqCirQueue* SCQ)
{
if (SCQ->fornt == SCQ->rear)
{
return 1;
}
return 0;
}

//Determine whether the queue is full
int IsFull(SeqCirQueue* SCQ)
{
//The tail pointer + 1 catches up with the head pointer, indicating that the queue is full
if ((SCQ->rear + 1) % MaxSize == SCQ->fornt)
{
return 1;
}
return 0;
}

//Queue operation
int EnterSeqCirQueue(SeqCirQueue* SCQ, DataType data)
{
if (IsFull(SCQ))
{
printf("The queue is full, cannot join!\n");
return 0;
}
SCQ->Queue[SCQ->rear] = data;
SCQ->rear = (SCQ->rear + 1) % MaxSize;   //Reset tail pointer
}

//Out of line operation
int DeleteSeqCirQueue(SeqCirQueue* SCQ,DataType* data)
{
if (IsEmpty(SCQ))
{
printf("The queue is empty!\n");
return 0;
}
*data = SCQ->Queue[SCQ->fornt];
SCQ->fornt = (SCQ->fornt + 1) % MaxSize;  //Reset queue head pointer
}

//Take the first element of the team
{
if (IsEmpty(SCQ))
{
printf("The queue is empty!\n");
return 0;
}
*data = SCQ->Queue[SCQ->fornt];
return *data;
}

//Empty queue
void ClearSeqCirQueue(SeqCirQueue* SCQ)
{
SCQ->fornt = SCQ->rear = 0;
}

//Print queue elements
void PrintSeqCirQueue(SeqCirQueue* SCQ)
{
assert(SCQ);   //Assert that SCQ is not empty
int i = SCQ->fornt;
if (SCQ->fornt < SCQ->rear)
{
for (; i < SCQ->rear; i++)
{
printf("%-3d", SCQ->Queue[i]);
}
}
else
{
for (i; i <SCQ->rear + MaxSize; i++)
{
printf("%-3d", SCQ->Queue[i]);
}
}
printf("\n");
}

int main()
{
SeqCirQueue SCQ;
DataType data;
//Initialize queue
InitSeqCirQueue(&SCQ);
//Join the team
EnterSeqCirQueue(&SCQ, 1);
EnterSeqCirQueue(&SCQ, 2);
EnterSeqCirQueue(&SCQ, 4);
EnterSeqCirQueue(&SCQ, 6);
EnterSeqCirQueue(&SCQ, 8);
EnterSeqCirQueue(&SCQ, 9);
EnterSeqCirQueue(&SCQ, 10);
EnterSeqCirQueue(&SCQ, 12);
EnterSeqCirQueue(&SCQ, 13);
printf("The elements in the queue are:\n");
//Print elements in queue
PrintSeqCirQueue(&SCQ);
EnterSeqCirQueue(&SCQ, 15);
//Out of the team
DeleteSeqCirQueue(&SCQ, &data);
printf("The outgoing elements are:%d\n", data);
printf("\n");
printf("The elements in the queue are:\n");
PrintSeqCirQueue(&SCQ);
printf("15 Join the team:\n");
EnterSeqCirQueue(&SCQ, 15);
printf("The elements in the queue are:\n");
PrintSeqCirQueue(&SCQ);
system("pause");
return 0;
}
```

The result is: after the element leaves the team, it will release space, and new elements can join the team, eliminating the "false overflow phenomenon".

# 3, Chain queue

Chained queue is a single linked list that restricts deletion and insertion only in the header and at the end of the table. The operation of chained queue is actually a single linked list operation, except that outgoing queue is carried out in the header and incoming queue is carried out at the end of the table. Refer to the following figure for queue entry and exit of chain queue:

```#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>
#include <assert.h>

typedef int DataType;
typedef struct Node
{
DataType _data;
struct Node* _next;

typedef struct
{

//Initialize queue
{
LQ->front = LQ->rear = pHead; //The head and tail of the team point to the head node
LQ->front->_next = NULL;
}

//Determine whether the queue is empty

{
if (LQ->front->_next == NULL)
{
return 1;
}
return 0;
}

//Queue operation

{
//Create a new node
assert(pNewNode);
pNewNode->_data = data;  //Assign the data element to the data field of the node
pNewNode->_next = NULL;  //Set the pointer field of the node to null
LQ->rear->_next = pNewNode;   //Point the tail pointer of the original queue to the new node
LQ->rear = pNewNode;      //Point the end of the queue pointer to the new node
}

//Out of line operation

{
if (IsEmpty(LQ))
{
printf("The queue is empty!\n");
return;
}
//pDel points to the queue head element. Since the queue head pointer front points to the header node, pDel points to the next node of the header node
*data = pDel->_data;   //Assign the element to be dequeued to data
LQ->front->_next = pDel->_next;  //Make the pointer to the head node point to the next node of pDel
//If there is only one element in the queue, empty the queue
if (LQ->rear = pDel)
{
LQ->rear = LQ->front;
}
free(pDel);   //Free the space pointed to by pDel
}

{
if (IsEmpty(LQ))
{
printf("Queue is empty!\n");
return 0;
}
pCur = LQ->front->_next;  //pCur points to the first element of the queue, that is, the next node of the header node
*data = pCur->_data;      //Assign the team head element value to data
return *data;             //Returns the value of the queue header element
}

//Empty queue

{
while (LQ->front != NULL)
{
LQ->rear = LQ->front->_next;  //The tail pointer points to the next node of the head pointer
free(LQ->front);              //Release the node pointed to by the queue head pointer
LQ->front = LQ->rear;         //The head pointer points to the tail pointer
}
}

//Print elements in queue

{
assert(LQ);
pCur = LQ->front->_next;
while (pCur)
{
printf("%-3d", pCur->_data);
pCur = pCur->_next;
}
printf("\n");
}
int main()
{
DataType data;
//Initialize queue
//Join the team
printf("The elements in the queue are:");
//Print elements in queue
printf("\n");
printf("The team head elements are:%d\n", data);
printf("\n");
//Out of the team
printf("The out of queue elements are:%d\n", data);
printf("\n");
printf("The elements in the queue are:");
printf("\n");
printf("The team head elements are:%d\n", data);
printf("\n");
ClearQueue(&LQ);
system("pause");
return 0;
}
```

The result is:

# 4, queue container

```Constructor:
queue<T> que;  //Implemented by template class
queue(const queue &que);  //copy constructor

Assignment operation:
queue & operator= (const queue &que); //Overload = operator

Data access:
push(elem);  //Join the team and add elements to the end of the team
pop();  //Remove the first element of the team head
back();  //Returns the last element
front();  //Returns the first element

Size operation:
empty();  //Determine whether the queue is empty
size();  //Returns the size of the stack
```
```#include <iostream>
#include <queue>
#include <string>

using namespace std;

//queue
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};

void test()
{
//Create queue
queue<Person> q;

//Prepare data
Person p1("coco",10);
Person p2("dudu", 20);
Person p3("kiki", 18);
Person p4("vivi", 24);

//Join the team
q.push(p1);
q.push(p2);
q.push(p3);
q.push(p4);

cout << "Queue size:" << q.size() << endl;

//As long as the queue is not empty, view the team head element and the team tail element to exit the queue
while (!q.empty())
{
cout << "Team leader element - name:" << q.front().m_Name << "  Age:" << q.front().m_Age << endl;

//View tail element
cout << "Tail element - name:" << q.back().m_Name << "  Age:" << q.back().m_Age << endl;

//Out of the team
q.pop();

cout << "Queue size:" << q.size() << endl;
}
}

int main()
{
test();

return 0;
}
```

The result is:

Topics: C data structure