Queue Storage Structure and common operations (implemented in c)
I. Like the stack, the queue has many important applications in algorithm design of the program and other branches of the computer, for example, the computer operating system's Priority Scheduling Algorithm for processes or jobs, the simulation algorithm for discrete events, and the problem of inconsistent running speeds between computer hosts and external devices. In fact, the essence of the queue is a linear table! It is only a special or restricted linear table, which is as follows: 1) Insert at one end of the table and delete at the other end. The inserted end is the end of the team, and the deleted end is the head of the team. That is to say, you can only delete elements in the header of a linear table and insert elements at the end of the table. The image is the faucet and water pipe, the water nozzle is the head of the team, the water pump is the end of the team, the pipe does not leak water. In this way, the flow of zookeeper is like this. 2) first-in-first-out (FIFO structure ). Obviously, we cannot operate elements in the middle of a table (Queue). We can only enter elements at the tail end, go out at the head, or similar to the train-to-tunnel process. (First in first out = FIFO structure) note that when the queue has no elements, we will say that the queue is an empty queue. 1. double-ended queue: Limit the insertion and deletion at both ends of the table. It is also a first-in-first-out (FIFO) structure, similar to a Railway Transition Network. There are not many applications in the actual program. This structure is further subdivided into three categories: 1) double-ended Queues with limited input: one endpoint can be inserted and deleted, and the other endpoint can only be deleted. 2) Dual-end queue with limited output: one endpoint can be inserted and deleted, and the other endpoint can only be inserted. 3) equivalent to two stacks connected at the bottom of the stack: restrict the elements inserted by the dual-end queue from a certain endpoint and can only be deleted at this endpoint. 2. A chain Queue (where there is a chain, there is a pointer) is represented by a chain table. Only a single-chain table inserted at the header and the end of the table is restricted. A chain queue is uniquely identified by a header pointer and a tail pointer. (Because it is not convenient to insert a table at the end of a table with only a header pointer ). For ease of operation, a header node is also added to the chain queue. Therefore, the condition for determining a null queue is that both the header pointer and the tail pointer point to the header node. The previous chain structure always uses a node structure to represent the linked list. In fact, it is not very convenient. Here we use the new storage structure. Defines a node structure and a queue structure. Two structures are nested. Copy code 1 # ifndef queue_Header_h 2 # define queue_Header_h 3 # include <stdio. h> 4 # include <stdlib. h> 5 # include <stdbool. h> 6 7 // Queue Node structure 8 typedef struct Node {9 int data; 10 struct Node * next; 11} Node, * Queue; 12 13 // Queue structure, nested 14 typedef struct {15 Queue front; 16 Queue rear; 17} LinkQueue; 18 19 // initialization 20 // The start must be an empty Queue, both the team end pointer and the team head pointer point to the header node 21 void initQueue (LinkQueue * queue) 22 {23 // initialize the header node 24 queue-> front = queue-> Rear = (Queue) malloc (sizeof (Node); 25 26 if (NULL = queue-> front) {27 exit (0 ); 28} 29 30 queue-> front-> next = NULL; 31} 32 33 // NULL 34 bool isEmpty (LinkQueue queue) 35 {36 return queue. rear = queue. front? True: false; 37} 38 39 // enter the queue. Only one end is in the queue and the other end is in the queue. Similarly, you do not need to determine that 40 void insertQueue (LinkQueue * queue, int temp) is in the queue) 41 {42 Queue q = (Queue) malloc (sizeof (Node); 43 44 if (NULL = q) {45 exit (0 ); 46} 47 // insert data 48 q-> data = temp; 49 q-> next = NULL; 50 // rear always points to the team end element 51 queue-> rear-> next = q; 52 queue-> rear = q; 53} 54 55 // team out, 56 void deleteQueue (LinkQueue * queue) 57 {58 Queue q = NULL; 59 60 if (! IsEmpty (* queue) {61 q = queue-> front-> next; 62 queue-> front-> next = q-> next; 63 // This sentence is critical, 64 if (queue-> rear = q) {65 queue-> rear = queue-> front; 66} 67 68 free (q ); 69} 70} 71 72 // traverse 73 void traversal (LinkQueue queue) 74 {75 int I = 1; 76 Queue q = queue. front-> next; 77 78 while (q! = NULL) {79 printf ("the % d element in the queue is: % d \ n", I, q-> data); 80 q = q-> next; 81 I ++; 82} 83} 84 85 // destroy 86 void destoryQueue (LinkQueue * queue) 87 {88 while (queue-> front! = NULL) {89 queue-> rear = queue-> front-> next; 90 free (queue-> front); 91 queue-> front = queue-> rear; 92} 93 94 puts ("destroyed successfully! "); 95} 96 97 # endif copy code test copy code 1 # include" queue. h "2 3 int main (int argc, const char * argv []) 4 {5 LinkQueue queue; 6 puts (" initialize queue "); 7 initQueue (& queue ); 8 traversal (queue); 9 10 puts ("0 1 2 3" inserted at the end of the team); 11 insertQueue (& queue, 0); 12 insertQueue (& queue, 1 ); 13 insertQueue (& queue, 2); 14 insertQueue (& queue, 3); 15 traversal (queue); 16 17 puts ("first-in-first-out, deleting a queue starts from scratch, 0 "); 18 deleteQueue (& queue); 19 traversa L (queue); 20 21 puts ("first-in-first-out, deleting a queue from the beginning, 1"); 22 deleteQueue (& queue); 23 traversal (queue ); 24 25 puts ("first-in-first-out, deleting a queue from the beginning, 2"); 26 deleteQueue (& queue); 27 traversal (queue); 28 29 puts ("first-in-first-out, delete a queue from the beginning, 3 "); 30 deleteQueue (& queue); 31 traversal (queue); 32 33 destoryQueue (& queue); 34 return 0; 35} copy the code result: at the end of the initialization queue, insert 0 1 2 3 queue 1st elements: 0 queue 2nd elements: 1 queue 3rd elements: 2 queue 4th elements are: 3. first-in-first-out: deletes a queue from the beginning. The first element of the 0 queue is: 1. The first element of the queue is: 2. The second element of the queue is: 2. Yes: 3. first-in-first-out: the first-out queue is deleted. The first-out queue has 1st elements: 2. The first-out queue has 2nd elements: 3. The first-in-first-out queue has been deleted, 2. The 1st elements of the queue are: 3. first-in-first-out, deleting the queue starts from the beginning, and 3 is destroyed successfully! Program ended with exit code: 0 3. ordered queue only allows you to delete an ordered table from the header and insert it at the end of the table. A group of sequential storage units are used to store data elements in the queue in sequence. Because the positions at the head and end of the team are changing, we also need to set the head and tail pointers. The header and tail pointer during initialization. The initial value must be set to 0. The value of the forward pointer increases by 1, and the value of the forward pointer increases by 1. When the header and tail pointers are equal, the queue is empty. In a non-empty queue, the header pointer always points to the Header element of the queue, and the tail pointer always points to the next position of the element at the end of the queue. If it is an empty queue, the head and tail pointers are equal. If the tail pointer is added to the queue, the header pointer remains unchanged. First-in-first-out, J1 first-in-first-out, rear + 1, and the tail pointer always points to the next element at the end of the team! For example, J2 enters the team, rear continues to + 1, J3 enters the team, and the tail pointer continues to add 1. When the team leaves the team, the tail pointer remains unchanged, and the header pointer is added with 1. Note that the first pointer is added with 1, first-in-first-out principle: J1 is deleted first, front + 1 is directed to J2, J2 is deleted, front + 1 is directed to J3, and J3 is deleted, the header pointer is equal to the tail pointer again, the queue is empty. In an ordered queue, when the tail pointer has pointed to the next position in the last position of the queue, if there are other elements in the queue, "overflow" will occur ". Location. If you join the team again, the system will overflow. 4. The "false overflow" problem of the sequential queue in which the cyclic queue is generated: the queue's storage space is not full, but it overflows. It is easy to understand. For example, although rear points to the next position in the last position, but some elements are also deleted in the front of the team, after the header pointer goes through the + 1 several times, there are a lot of empty positions left behind, but the ordered queue is still dumbly thinking that there are more elements to join the queue, it will overflow! It must be unreasonable. So the cyclic queue was born! There are two feasible methods to solve the "false overflow" problem: (1). Pan the elements to the first part of the queue. Low efficiency. No. (2) Insert new elements into the first position to form a cyclic queue. the inbound and outbound elements are still carried out in accordance with the "first-in-first-out" principle. High operation efficiency and high space utilization. Although loop queue is used to solve the problem of false overflow, a new problem occurs-empty determination, because it cannot be determined whether the loop queue is empty or full only by front = rear. For example, this is an empty loop queue. This is a full loop queue. Solution: (1) set a Boolean variable to distinguish the empty and full queues. (2) use less space of one element. It is agreed to test whether adding 1 to the end pointer in the loop before entering the queue is equal to the head pointer. If the result is equal, the team is considered full. (most commonly used) (3), use a counter to record the total number of elements in the queue. For the 2nd solutions, one element space must be sacrificed, so testing is required when you join the team. The addition of 1 in the loop can be described as follows: copy the Code 1 if (rear + 1 = MAXQSIZE) 2 3 rear = 0; 4 5 else6 7 rear ++; copy the code using the modulo operation to simplify it: 1 rear = (rear + 1) % MAXQSIZE basic operation copy code 1 # ifndef ___ queue_Header_h 2 # define ___ queue_Header_h 3 # include <stdio. h> 4 # include <stdlib. h> 5 # define MAX_SIZE 5 6 7 typedef struct {8 int * base; 9 int rear; // If the queue is not empty, point to the next position of the team's tail element 10 int front; // initially point to header 11} CirularQueue; 12 13 // initialize 14 void initQueue (CirularQueue * queue) 15 {16 queue-> base = (int *) malloc (MAX_SIZE * sizeof (int )); 17 18 if (NULL = queue-> base) {19 exit (0); 20} 21 22 queue-> front = queue-> rear = 0; 23} copy the code and obtain the length. Copy the code. // obtain the length. int getLength (CirularQueue queue). {// in this way, return (queue. rear-queue. front + MAX_SIZE) % MAX_SIZE;} copy the first case of the Code. The second case is length. The second case is length. Using the modulo operation, the two cases are combined into one! Copy the code // enter the queue and determine whether the void insertQueue (CirularQueue * queue, int e) {if (queue-> rear + 1) % MAX_SIZE = queue-> front) {puts ("the cyclic queue is full! ");} Else {queue-> base [queue-> rear] = e; queue-> rear = (queue-> rear + 1) % MAX_SIZE ;}} when the code is copied as follows, it will be full, causing a loss of space and no elements are stored. Make it easy to determine full replication code 1 // departure 2 void deleteQueue (CirularQueue * queue) 3 {4 if (queue-> front = queue-> rear) {5 puts ("the queue is empty! "); 6} 7 else 8 {9 queue-> front = (queue-> front + 1) % MAX_SIZE; 10} 11} 12 13 // traverse 14 void traversal (CirularQueue queue) 15 {16 int q = queue. front; 17 18 for (int I = 0; I <getLength (queue); I ++) {19 printf ("the % d element of the cyclic queue is % d \ n", I + 1, queue. base [q]); 20 q ++; 21} 22} 23 24 # endif copy code test copy code 1 # include "Header. h "2 3 int main (int argc, const char * argv []) {4 CirularQueue queue; 5 puts (" cyclic queue initialization: "); 6 InitQueue (& queue); 7 8 puts ("length after cyclic queue initialization:"); 9 printf ("% d \ n", getLength (queue )); 10 11 puts ("the five elements in the cyclic queue are queued. The total length is 5, but one location space is lost. The four elements are actually stored. First-in-first-out principle: "); 12 puts (" loop queue element 0 "); 13 insertQueue (& queue, 0); 14 puts (" loop queue element 1 "); 15 insertQueue (& queue, 1); 16 puts ("queue element 2"); 17 insertQueue (& queue, 2 ); 18 puts ("cycle queue element 3"); 19 insertQueue (& queue, 3); 20 21 puts ("loop queue element traversal:"); 22 traversal (queue ); 23 24 puts ("the cyclic queue element continues to join the queue and cannot be completed:"); 25 insertQueue (& queue, 4); 26 27 puts ("after the cyclic queue element 0 leaves the queue, first-in-first-out principle: "); 28 deleteQueue (& queue); 29 traversal (queue); 30 31 puts (" after the cyclic queue element 1 leaves the queue, first First-in-first-out principle: "); 32 deleteQueue (& queue); 33 traversal (queue); 34 35 puts (" after element 2 of the loop queue leaves the queue, first-in-first-out principle :"); 36 deleteQueue (& queue); 37 traversal (queue); 38 39 puts ("after the queue element 3 is out of the queue, the first-in-first-out principle is:"); 40 deleteQueue (& queue ); 41 traversal (queue); 42 43 puts ("all four elements are deleted, and the cyclic queue is empty:"); 44 deleteQueue (& queue); 45 46 traversal (queue ); 47 48 return 0; 49} copy the code result. cyclic queue initialization: The length after cyclic queue initialization: 0. cyclic queue: five elements are added to the queue. The total length is 5, but one location space is lost, four elements are actually stored. First-in-first-out principle: Element 0 in the cyclic queue element 1 in the cyclic queue element 2 in the cyclic queue element 3 in the cyclic queue element traversal: the 1st elements of the cyclic queue are 0. The 2nd elements of the cyclic queue are the 3rd elements of the 1 cyclic queue. The 4th elements of the 2 cyclic queue are the 3 cyclic queue elements, unable to complete: the cyclic queue is full! After the element 0 in the cyclic queue leaves the queue, the first-in-first-out principle is as follows: the first element of the cyclic queue is the first element of the 1 cyclic queue. The second element of the 2 cyclic queue is the third cyclic queue element. The first element is the first element: the first element of the cyclic queue is 2. The first element of the cyclic queue is 3. The first element is 3: the first element of the cyclic queue is 3: The cyclic queue element 3. After leaving the queue, the four elements are deleted. The cyclic queue is empty. The queue is empty! Program ended with exit code: 0 conclusion: If you need to loop the queue, you must set the maximum length of the queue. Otherwise, the determination cannot be completed. If you do not know the maximum length, then you should use the blockchain. Like the stack in program design, the queue has many applications and is not yet complete.