# Study notes: Part II queue

## Part II queue

### 1. Definition of queue

A queue is a linear table that only allows insertion at one end and deletion at the other end.

Queue is a first in first out linear table, called FIFO for short. The end that allows insertion is called the tail of the queue, and the end that allows deletion is called the head of the queue. ### 2. Abstract data type of queue

```ADT Queue( Queue)
Data
Elements of the same linear table have the same type, and adjacent elements have precursor and successor relationships.
Operation
InitQueue(&Q):Initialize the operation and create an empty queue Q.
DestoryQueue(&Q):If queue Q If it exists, destroy it.
ClearQueue(&Q):Queue Q Empty.
QueueEmpty(Q):If queue Q Null, return true，Otherwise return false.
GetHead(Q,&e):If the queue exists and is not empty, use e Return queue Q Team head element.
EnQueue(&Q,e):If queue Q Existing, insert new element e To queue Q And called the tail element.
DeQueue(&Q,&e):Delete queue Q Squadron head element, and use e Returns its value.
QueueLength(Q):Return queue Q Number of elements.
```

### 3. Circular queue (sequential storage structure)

We call this sequential storage structure of queue head to tail as circular queue.

```//Sequential storage structure of queue
typedef struct{
QElemType *base; //Initialized dynamically allocated storage space
int rear; //Tail index
}SqQueue;
```

#### Basic operations of circular queue:

##### Queue initialization:
```Status InitQueue(SqQueue &Q){
Q.base =(QElemType *)malloc(MAXQSIZE*sizeof(SqQueue));
if(!Q.base)
exit(OVERFLOW);
Q.front = Q.front = 0;
return OK;
}
```
##### Queue destruction:
```Status DestoryQueue(SqQueue &Q){
while(Q.front!=Q.rear){
free(&Q.base[Q.front]);
Q.front = (Q.front + 1) % MAXQSIZE;
}
return OK;
}
```
##### Emptying of queue:
```Status ClearQueue(SqQueue &Q){
Q.front=Q.rear=0;
return OK;
}
```
##### Determine whether the queue is empty:
```Status QueueEmpty(SqQueue Q){
if(Q.front==Q.rear) // Flag for empty queue
return TRUE;
else
return FALSE;
}
```
```Status GetHead(SqQueue Q,QElemType &e){
if(Q.front == Q.rear)
return ERROR;
e = Q.base[Q.front];
return OK;
}
```
##### Join the team:
```Status EnQueue(SqQueue &Q,QElemType e){
if((Q.rear+1) % MAXQSIZE == Q.front)
return ERROR;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXQSIZE;
return OK;
}
```
##### Out of the team:
```Status DeQueue(SqQueue &Q,QElemType &e){
if(Q.front == Q.rear)
return ERROR;
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXQSIZE;
return OK;
}
```
##### Return queue length:
```int QueueLength(SqQueue Q){
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}
```
##### Total test code:
```#include<stdio.h>
#include<stdlib.h>

#define MAXQSIZE 10 / / maximum queue length

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1

typedef int QElemType;
typedef int Status;

//Sequential storage structure of queue
typedef struct{
QElemType *base; //Initialized dynamically allocated storage space
int rear; //Tail index
}SqQueue;

Status InitQueue(SqQueue &Q){
Q.base =(QElemType *)malloc(MAXQSIZE*sizeof(SqQueue));
if(!Q.base)
exit(OVERFLOW);
Q.front = Q.front = 0;
return OK;
}

Status EnQueue(SqQueue &Q,QElemType e){
if((Q.rear+1) % MAXQSIZE == Q.front)
return ERROR;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXQSIZE;
return OK;
}

Status DeQueue(SqQueue &Q,QElemType &e){
if(Q.front == Q.rear)
return ERROR;
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXQSIZE;
return OK;
}

if(Q.front == Q.rear)
return ERROR;
e = Q.base[Q.front];
return OK;
}

Status ClearQueue(SqQueue &Q){
Q.front=Q.rear=0;
return OK;
}

Status QueueEmpty(SqQueue Q){
if(Q.front==Q.rear) // Flag for empty queue
return TRUE;
else
return FALSE;
}

int QueueLength(SqQueue Q){
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

Status DestoryQueue(SqQueue &Q){
while(Q.front!=Q.rear){
free(&Q.base[Q.front]);
Q.front = (Q.front + 1) % MAXQSIZE;
}

return OK;
}

Status visit(QElemType c)
{
printf("%d ",c);
return OK;
}

//Each element in queue Q is output from the head of the queue to the tail of the queue
Status QueueTraverse(SqQueue Q)
{
int i;
i=Q.front;
while((i+Q.front)!=Q.rear)
{
visit(Q.base[i]);
i=(i+1)%MAXQSIZE;
}
printf("\n");
return OK;
}

int main()
{
Status j;
int i=0,l;
QElemType d;
SqQueue Q;
InitQueue(Q);
printf("After initializing the queue, is the queue empty?%u(1:Null 0:no)\n",QueueEmpty(Q));

printf("Please enter an integer queue element(No more than%d individual),-1 Is an early terminator: ",MAXQSIZE-1);
do
{
/* scanf("%d",&d); */
d=i+100;
if(d==-1)
break;
i++;
EnQueue(Q,d);
}while(i<MAXQSIZE-1);

printf("Queue length is: %d\n",QueueLength(Q));
printf("Is the queue empty now?%u(1:Null 0:no)\n",QueueEmpty(Q));
printf("continuity%d Delete element by team leader,Insert element at end of queue:\n",MAXQSIZE);
for(l=1;l<=MAXQSIZE;l++)
{
DeQueue(Q,d);
printf("The deleted element is%d,Inserted element:%d \n",d,l+1000);
/* scanf("%d",&d); */
d=l+1000;
EnQueue(Q,d);
}
l=QueueLength(Q);

printf("Now the elements in the queue are: \n");
QueueTraverse(Q);
printf("We've inserted it at the end of the team%d Elements\n",i+MAXQSIZE);
if(l-2>0)
printf("Now deleted by team leader%d Elements:\n",l-2);
while(QueueLength(Q)>2)
{
DeQueue(Q,d);
printf("The deleted element value is%d\n",d);
}

if(j)
printf("Now the team head element is: %d\n",d);
ClearQueue(Q);
printf("After emptying the queue, Is the queue empty?%u(1:Null 0:no)\n",QueueEmpty(Q));
return 0;
}
```
##### Operation results: ### 4. Chain storage structure and implementation of queue

The chain storage structure of queue is actually a single chain list of linear table, but it can only end in and end out. We call it chain queue for short.

For the convenience of operation, we point the queue head pointer to the head node of the chain queue, and the queue tail pointer to the terminal node. When the queue is empty, both front and rear point to the head node. ```typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
QueuePtr front,rear;
```

#### Basic operations of chain queue:

##### Queue initialization:
```Status InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
if(!Q.front)
exit(OVERFLOW);
Q.front->next=NULL;
return OK;
}
```
##### Queue destruction:
```Status DestroyQueue(LinkQueue &Q)
{
while(Q.front)
{
Q.rear=Q.front->next;
free(Q.front);
Q.front=Q.rear;
}
return OK;
}
```
##### Emptying of queue:
```Status ClearQueue(LinkQueue *Q)
{
QueuePtr p,q;
Q->rear=Q->front;
p=Q->front->next;
Q->front->next=NULL;
while(p)
{
q=p;
p=p->next;
free(q);
}
return OK;
}
```
##### Determine whether the queue is empty:
```Status QueueEmpty(LinkQueue Q)
{
if(Q.front==Q.rear)
return TRUE;
else
return FALSE;
}
```
```Status GetHead(LinkQueue Q,QElemType &e)
{
QueuePtr p;
if(Q.front==Q.rear)
return ERROR;
p=Q.front->next;
e=p->data;
return OK;
}
```
##### Join the team: ```Status EnQueue(LinkQueue &Q,QElemType e)
{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if(!s)
exit(OVERFLOW);
s->data=e;
s->next=NULL;
Q.rear->next=s;
Q.rear=s;
return OK;
}
```
##### Out of the team: ```Status DeQueue(LinkQueue &Q,QElemType &e)
{
QueuePtr p;
if(Q.front==Q.rear)
return ERROR;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p)
Q.rear=Q.front;
free(p);
return OK;
}
```
##### Return queue length:
```int QueueLength(LinkQueue Q)
{
int i=0;
QueuePtr p;
p=Q.front;
while(Q.rear!=p)
{
i++;
p=p->next;
}
return i;
}
```
##### Total test code:
```#include "stdio.h"
#include "stdlib.h"

#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 / * initial allocation of storage space*/

typedef int Status;

typedef int QElemType; /* QElemType The type depends on the actual situation. It is assumed to be int */

typedef struct QNode	/* Node structure */
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;

typedef struct			/* Linked list structure of queue */
{
QueuePtr front,rear; /* Head and tail pointer */

Status visit(QElemType c)
{
printf("%d ",c);
return OK;
}

{
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
if(!Q.front)
exit(OVERFLOW);
Q.front->next=NULL;
return OK;
}

{
while(Q.front)
{
Q.rear=Q.front->next;
free(Q.front);
Q.front=Q.rear;
}
return OK;
}

{
QueuePtr p,q;
Q.rear=Q.front;
p=Q.front->next;
Q.front->next=NULL;
while(p)
{
q=p;
p=p->next;
free(q);
}
return OK;
}

{
if(Q.front==Q.rear)
return TRUE;
else
return FALSE;
}

{
int i=0;
QueuePtr p;
p=Q.front;
while(Q.rear!=p)
{
i++;
p=p->next;
}
return i;
}

{
QueuePtr p;
if(Q.front==Q.rear)
return ERROR;
p=Q.front->next;
e=p->data;
return OK;
}

{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if(!s)
exit(OVERFLOW);
s->data=e;
s->next=NULL;
Q.rear->next=s;
Q.rear=s;
return OK;
}

{
QueuePtr p;
if(Q.front==Q.rear)
return ERROR;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p)
Q.rear=Q.front;
free(p);
return OK;
}

{
QueuePtr p;
p=Q.front->next;
while(p)
{
visit(p->data);
p=p->next;
}
printf("\n");
return OK;
}

int main()
{
int i;
QElemType d;
i=InitQueue(q);
if(i)
printf("Successfully constructed an empty queue!\n");
printf("Empty queue?%d(1:Null 0:no)  ",QueueEmpty(q));
printf("The length of the queue is%d\n",QueueLength(q));
EnQueue(q,-5);
EnQueue(q,5);
EnQueue(q,10);
printf("Insert 3 elements(-5,5,10)after,The length of the queue is%d\n",QueueLength(q));
printf("Empty queue?%d(1:Null 0:no)  ",QueueEmpty(q));
printf("The elements of the queue are:");
QueueTraverse(q);
if(i==OK)
DeQueue(q,d);
printf("The team head element was deleted%d\n",d);
if(i==OK)
printf("The new team leader element is:%d\n",d);
ClearQueue(q);
printf("After emptying the queue,q.front=%u q.rear=%u q.front->next=%u\n",q.front,q.rear,q.front->next);
DestroyQueue(q);
printf("After destroying the queue,q.front=%u q.rear=%u\n",q.front, q.rear);

return 0;
}
```
##### Operation results: ### 5. Summary:

(1) For the comparison between circular queue and chain queue, in terms of time, their basic operations are constant time, that is, they are all 0 (1) However, the circular queue applies for space in advance and does not release it during use. For the chain queue, there will be some time overhead for each application and release node. If the queue is in and out frequently, there is still a slight difference between the two. In terms of space, the circular queue must have a fixed length, so there is a problem of the number of storage elements and waste of space Queue does not have this problem. Although it requires a pointer field and will incur some spatial overhead, it is also acceptable. Therefore, chain queue is more flexible in space.

In general, when the maximum queue length can be determined, it is recommended to use circular queue. If you cannot estimate the length of the queue, use chain queue.

(2)

Stack and queue, which are special linear tables, but restrict insert and delete operations.

A stack is a linear table that is restricted to insert and delete operations only at the end of the table.

A queue is a linear table that only allows insertion at one end and deletion at the other.

Both of them can be realized by the sequential storage structure of linear table, but they all have some disadvantages of sequential storage.

Therefore, they have their own skills to solve this problem.

For queues, in order to avoid moving data during array insertion and deletion, circular queues are introduced, so that the head and tail of the queue can change circularly in the array. The time loss of moving data is solved, so that the time complexity of O(n) is changed to 0 (1).

They can also be realized through the chain storage structure, which is basically the same as the linear table in principle. 