Queue in C language (sequential queue and chain queue)-concept and basic operation

Preface

It’s been a long time since I updated, and I said I would post the results until now. After the gossip is finished, the content is officially started.
Queue-as the name suggests, it is also an extremely important structure in a linear table.
The difference with the stack is that the stack inserts and deletes elements at one end, while the queue, delete from the head of the queue, insert at the end of the queue, just like the queuing in daily life, it is still more vivid.
This article will briefly introduce the concept and operating functions of queues, and explain some basic algorithms of sequential queues (using arrays) and chained queues (using linked lists).

1. Related concepts of queues

1. Queue and its operation (first in, first out)

1.1 Related concepts

(1) Queue: It is only allowed to delete elements at one end of the table, and a linear table with elements inserted at the other end
(2) Empty queue: a queue without elements
(3) Head of the queue: Only one end of the queue where elements are allowed to be deleted, also known as head, front
(4) tail of the queue: only one end of the queue is allowed to insert elements, also known as rear, tail
(5) enqueue (enter the queue): insert a new element at the end of the
queue (6) dequeue: delete one from the queue Element, that is, delete the element at the head of the team.
Note: Entering and leaving the team can be compared to a queue

1.2 The basic operation of the queue
(1) InitQueue(q): initialize, set q to an empty queue
(2) QueueEmpty(q): determine whether q is an empty queue
(3) EnQueue(q, e): insert e into the queue q tail end
(4) DeQueue (q, e ): removal of the first element of the queue q, assigned to E
(. 5) GetHead (q, E); first read queue elements, assigned to E
(. 6) QueueClear (q) : Set q to empty queue

Two, the basic operation of chain queue

1. Chained queue: a queue that uses a chained structure for storage, generally represented by a singly linked list with a header node

In order to improve the efficiency of insertion and deletion, two pointers are set in the head pointer.
General forms:
(1) Q.front: the first pointer of the team, pointing to the head node
(2) Q.rear: the last pointer of the team, pointing to the end of the team.
Note : When the queue is empty, (1) (2) are executed at the head node
(3) Q.front->data: do not put elements
(4) Q.fornt->next: point to the first node a1

2. Define the node type

(1) The type of node storing the element: data field and pointer field

//定义结点类型
typedef struct Qnode
{
    
    
	ElemType data;//其中数据域data为抽象元素类型
	struct Qnode *next;//其中next为指针类型 
}Qnode,*QueuePtr;//其中,Qnode为结点类型, QueuePtr:指向Qnode的指针类型

(2) Node type composed of head and tail pointers

//由头、尾指针组成的结点类型
typedef struct
{
    
    
	Qnode *front;//头指针
	Qnode *rear;//尾指针 
}LinkQueue;//链式队列类型 

(3) Generate empty queue algorithm: initialize the queue

//生成空队列算法:初始化队列	
#define LENG sizeof(Qnode)//求结点所占的单元数
LinkQueue InitQueue()//生成仅带表头结点的空队列Q
{
    
    
	LinkQueue Q;//说明变量Q
	Q.front = Q.rear = (QueuePtr)malloc(LENG);//生成表头结点
	Q.front->next = NULL;//表头结点的next为空指针
	return Q;//返回Q的值 
} 

(4) Insert a new element x when the queue is (not) empty

//(非)空队列时插入新元素x	
LinkQueue Enqueue(LinkQueue Q,ElemType e)
{
    
    
	Qnode *p;//说明变量p
	p = (Qnode*)malloc(LENG);//生成新元素结点
	p->data = e;//装入元素e
	p->next = NULL;//为队尾结点
	Q.rear->next = p;//插入新结点
	Q.rear = p;//修改尾指针
	return Q;//返回Q的新值 
} 

3. Deletion of elements (change the header node)

Note: If the original queue has only one node, you also need to consider the tail pointer
chain queue dequeuing algorithm

//链式队列的出队算法	
LinkQueue DelQueue(LinkQueue Q,ElemType *e)
{
    
    
	Qnode *p;//声明变量p
	if (Q.front==Q.rear)//若原队列为空
	{
    
    
		printf ("Empty queue");//空队列
		return Q; 
	}
	p = Q.front->next;//p指向要删除的队头结点
	(*e) = p->data;//取出元素
	Q.front->next = p->next;//删除队头结点
	if (Q.rear==p)//若原队列只有1个结点
	{
    
    
		Q.rear = Q.front;//修改尾指针 
	}
	free(p);//释放被删除的空间
	return Q;//返回出队后的Q 
}

Three, the basic operation of the sequential queue

1. Sequential queues and "false overflow"

Suppose that a one-dimensional array Q[0…5] is used to represent the sequential queue.
Let f point to the head element and r point to an empty cell after the tail element.
(1) After initialization: empty queue r=f
(2) After element ABC enters the queue: f Point to A, r points to the next unit after C (ie Q[3])
(3) After ABC leaves the queue: f is moved to r, then the empty queue f=r
(4) After DEF enters the queue, r is moved to behind F (Q[5]) after
(5) if G wants to enter at this time, it will be judged as a false overflow,
but at this time Q[0], Q[1], etc. are still empty

2. Method one to solve the false overflow: move the element

(6) After DEF moves to the front end, it occupies Q[0], Q[1], and Q[2]. At this time, fr also moves.
(7) After G enters the team, r points to Q[3]
. Disadvantages of this method: more time-consuming , Moving elements are expensive

3. Method 2: Use Q as a circular table (circular queue)

That is, at (4), r will point to Q[0] again.
In (5), G will be placed on Q[0] when G wants to enter the team, and r will move backward to point to Q[1]
(6) At this time, HI After entering the queue, the queue is full, and f=r
causes a problem. When f=r, is the queue empty or full (ambiguity)

(1) Ambiguity solution

Option 1: Add an identification variable.
Option 2: Reserve the last unit and do not use it, that is, test before entering the queue.
If r+1==f, it indicates that the last unit is left, and the queue
is considered to be full at this time. That is, if the queue is Q[0...maxleng-1], a total of maxleng-1 elements

(2) The full queue condition of the circular queue
When r+1f or (f0)&&(rmaxleng-1),即:(r+1)%maxlengf is full queue,
empty queue condition is still r==f

4. Examples of sequential queue algorithms

(1) Define the C type of the queue

//顺序队列算法举例:定义队列的C类型
#define MAXLENG 100
typedef struct
{
    
    
	ElemType elem[MAXLENG];
	int front,rear;//分别指向队首结点和队尾结点后的下一个单元 
}SeQueue;
SeQueue Q;//定义结构变量Q表示队列 

(2) En_Queue enqueue algorithm

//假设用Q表示顺序队列,e为进队元素
int En_Queue (SeQueue &Q,ElenType e)
{
	if ((Q.rear+1)%MAXLENG==Q.front)//若Q已满,退出
		return ERROR;
	Q.elem[Q.rear] = e;//装入新元素e
	Q.rear++;//尾指针后移一个位置
	Q.rear = Q.rear%MAXLENG;//为循环队列
	return OK; 
} 
在这里插入代码片

(3) Dequeue algorithm De_Queue

//出队算法De_Queue
int De_Queue
{
    
    
	if (Q.front==Q.rear)//Q为空队列,退出
		return ERROR;
	e = Q.elem[Q.front];//取走队头元素,赋值给e
	Q.front = (Q.front+1)%MAXLENG;//循环后移到一个位置
	return OK; 
 } 
 

to sum up

In general, the determination of empty and full queues is much more complicated than that of the stack, and false overflows may occur. Because it is deleted at the head of the line, it takes more time to solve the problem by moving elements. Therefore, the chain queue has its advantages. The requirement for the computer is also lower than that of the array, and no continuous space is required. When storing a lot of data, chain queues can be used.
ps: The code is not original.
If there are any errors, please correct me.
The next article will introduce some special matrix operations.

Guess you like

Origin blog.csdn.net/qq_51308373/article/details/115057817