Data Structure--Basic Concept and Application of Queue

​ Stacks and queues are two important linear structures. From the perspective of data structure, stacks and queues are also linear tables. The special feature is that the basic operations of stacks and queues are a subset of linear table operations. They are linear tables with limited operations. Therefore, they can be called limited data. structure.

​ But on the other hand, from the perspective of data types, stacks and queues are two important abstract data types that are quite different from linear tables. And stacks and queues are widely used in various software systems because of their characteristics, and learning them is of great help to us. Therefore, in addition to discussing the definition, representation and implementation of stacks and queues, this article will also give some examples of applications.

In the previous article, we discussed the concept of the stack . In this article, we will continue to discuss the queue.

1. The basic concept of queue

​Definition of Queue : A queue is called a team for short, and it is also a linear table with restricted operations. It is restricted to only allow insertion at one end of the table and deletion at the other end of the table. The end that can be inserted is called the tail (Rear), and the end that can be deleted is called the front (front).

Resource Allocation Map

​Characteristics of the queue : The characteristics of the queue can be summed up as First in First out (FIFO).

​ Queues are more common in our lives. For example, we often line up to buy things, and wait for the 12306 ticket purchase queue; when a train enters a tunnel, each car is an element of the team, and the first car to enter is always the first to leave tunnel.

Resource Allocation Map

2. The storage structure of the queue

There are two main storage structures for queues, sequential queues and chain queues. The definition of the sequential queue is as follows. It can be seen that the core of the sequential queue is a continuous storage space, which is implemented here using an array.

typedef struct {
    
    
  //用于存放队列中的元素
  int data[maxSize];
  //队首指针
  int front;
  //队尾指针
  int rear;
} SqQueue;		

​ The chain team is defined as follows. It can be seen that the chain team uses a linked list to store the stack and uses the tail insertion method to create a team. The definition of chain team is more complicated, which is divided into two parts: team node and chain team:

//队结点
typedef struct QNode {
    
    
  //数据域
  int data;
  //指针域
  struct QNode * next;
} QNode;

//链队类型
typedef struct {
    
    
  //队头指针
  struct QNode * front;
  //队尾指针
  struct QNode * rear;
} LiQueue;
Resource Allocation Map

​ For queues, there are also two storage structures. Generally speaking, we also choose sequential queues.

​ Note: In some places, when defining the queue, for the convenience of storage, a head node will be added to the chain team, and the head pointer will point to the head node . At this time, the judgment condition of the empty queue becomes that both the head pointer and the tail pointer point to the head node (the tail pointer points to the head node, because the point of the front remains unchanged). The storage structure is shown in the figure below:

Resource Allocation Map

3. Definition and basic operations of sequential queues

3.1 Circular Queue

Similar to the sequential stack, in the sequential storage structure of the queue, in addition to using a group of storage units with continuous addresses to sequentially store the elements from the head of the queue to the tail of the queue, two pointers front and rear need to be attached to indicate the elements at the head of the queue respectively and the position of the tail element of the queue. For the convenience of description in C language, here we agree: when initializing an empty queue, let front=rear=0, whenever a new queue tail element is inserted, the "tail pointer is incremented by 1"; whenever a queue head element is deleted , "the head pointer is incremented by 1". Therefore, in a non-empty queue, the head pointer always points to the head element of the queue, and the tail pointer always points to the
next position of the tail element of the queue, as shown in the figure below.

Resource Allocation Map

​ Assuming that the maximum space currently allocated for the queue is 6, when the queue is in the state of (d) above, no new elements at the end of the queue can be inserted, otherwise an out-of-bounds exception will occur due to an array out of bounds. However, at this time, it is not appropriate to redistribute storage to expand the array space like the sequential stack, because the actual available space of the queue is not full. A more ingenious way is to fabricate the sequential queue as a circular space, as shown in the figure below, which is called a circular queue .

Resource Allocation Map

​ Imagine that the array "turns" into a ring, and let rear and front walk along the ring, so that there will never be a situation where the two reach the end of the array and cannot continue to go down. This is a circular queue. The circular queue is an improved sequential queue, and the entry and exit of elements are shown in the figure below:

Resource Allocation Map

​ In the figure above, the progress of the queue and the change of the queue are as follows:

① Enter two elements from the empty team, at this time, the front points to 0, and the rear points to 2.

② Enter 4 elements and leave 3 elements. At this time, front points to 3 and rear points to 6.

③ 2 elements enter the queue and 4 elements leave the queue. At this time, the front points to 7, and the rear points to 0.

​ From the change process from ① to ③, it can be seen that after the entry and exit of elements, even if the rear and front have reached the end of the array (as shown in ③ in the figure), elements can still continue to enter the queue, because the two pointers are not along Instead of walking in a straight line with the array subscript increasing, it walks along a ring, and automatically returns to the starting position of the array when it reaches the end of the array.

From the above analysis, we can also see that ordinary sequential queues have defects, so we will use circular queues in actual use. The sequential queues we will discuss later are mainly circular queues. In order to ensure the judgment of whether the queue is empty or full, the circular queue needs to sacrifice a storage space.

3.2 Elements of circular queues

​ The circular queue qu also has four elements, which are two special states: empty and full ; two operations: entering and exiting the queue .

​Queue empty status : qu.rear == qu.front

​Queue full status : (qu.rear+1)%maxSize == qu.front

​Enqueue operation :qu.data[qu.rear]=x; qu.rear = (qu.rear+1)%maxSize;

​Dequeue operation :x = qu.data[qu.front]; qu.front = (qu.front+1)%maxSize;

​ Note: The above code is to operate the data first and move the pointer when entering and exiting the queue; there may be other orders, but they are essentially the same.

3.3 Basic operation of circular queue

​Initialize the queue

void initQueue(SqQueue *qu){
    
    
  qu->front = qu->rear = 0;
}

​Determine whether the team is empty

//如果为空,返回1,否则返回0
int isEmpty(SqQueue qu){
    
    
    if(qu.rear == qu.front){
    
    
        return 1;
    }
    return 0;
}

​Into the queue operation

int enQueue(SqQueue *qu, int x){
    
    
    if((qu->rear+1)%maxSize == qu->front){
    
    
        printf("队满,无法入队!");
        return 0;
    }
    qu->data[qu->rear] = x;
    qu->rear = (qu->rear+1) % maxSize;
    return 1;
}

​Dequeue operation

int deQueue(SqQueue *qu, int *x){
    
    
    if(qu->rear == qu->front){
    
    
        printf("队空,无法出队!");
        return 0;
    }
    *x = qu->data[qu->front];
    qu->front = (qu->front+1) % maxSize;
    return 1;
}

​ In the exam, the team is generally used as an auxiliary structure to solve other problems, so in general, the definition and operation of the team can be written very simply, such as:

//两句话定义一个队
int queue[maxSize];
int front = rear = 0;
//入队
queue[rear] = x;
rear = (rear + 1) % maxSize;

//出队
x = queue[front];
front = (fron + 1) % maxSize;

4. Definition and basic operation of chain team

4.1 Elements of chain team

​ For the chain team lqu, there are also four elements, which are two special states: the team is empty and the team is full ; two operations: entering the team and leaving the team .

​Empty queue : lqu->rear == NULL or lqu->front == NULL, indicating that the stack is empty.

​Queue full : Under normal circumstances, there is no situation of full queue (unless the memory is insufficient and new nodes cannot be applied for).

Enqueue operation : The node where the element is located is pointed to by the pointer p, and the node is inserted using the tail insertion method.

//尾插法
lqu->rear->next = p;
lqu->rear = p;

​Dequeue operation : the popped element is stored in x

//p指向出栈结点
p = lqu->front;
x = p->data;
//队首指针指向下一个结点
lqu->front = p->next;
free(p);

​ The dynamic schematic diagram of enqueue and dequeue operation is as follows,

Resource Allocation Map

4.2 Basic operation of chain team

​Initialize the queue

void InitLinkedQueue(LiQueue *lqu){
    
    
    lqu = (LiQueue *) malloc(sizeof(LiQueue));
    lqu -> front =NULL;
    lqu -> rear = NULL;
}

​Determine whether the team is empty

int isLinkedEmpty(LiQueue lqu){
    
    
    if(lqu.rear == NULL || lqu.rear == NULL){
    
    
        return 1;
    }
    return 0;
}

​Enqueue operation

void enLinkedQueue(LiQueue *lqu, int x){
    
    
    //创建一个节点p
    QNode *p = (QNode *) malloc(sizeof(QNode));
    p->data = x;
    p->next = NULL;
    
    //需要判断队列是否为空,如果为空,需要同时修改front指针的值
    if(lqu->rear == NULL){
    
    
        lqu->rear = lqu ->front = p;
    } else{
    
    
        lqu->rear->next = p;
        lqu->rear = p;
    }
}

​Dequeue operation

int deLinkedQueue(LiQueue *lqu, int *x){
    
    
    if(lqu->rear == NULL){
    
    
        printf("队空,无法出队!");
        return 0;
    }
    QNode *p = lqu->front;
    //如果队中只有一个结点,需要同时修改rear指针的值
    if(lqu->front == lqu->rear){
    
    
        lqu->rear = lqu ->front = NULL;
    } else{
    
    
        lqu->front = p->next;
    }
    *x = p->data;
    free(p);
    return 1;
}

​Main function test code

int main(int argc, const char * argv[]) {
    
    
    // insert code here...
    LiQueue lqu;
  	int x;
    InitLinkedQueue(&lqu);
    printf("st.top:%d\n", lqu.front);
    printf("Queue is Empty:%d\n", isLinkedEmpty(lqu));
    enLinkedQueue(&lqu, 1);
    enLinkedQueue(&lqu, 2);
    enLinkedQueue(&lqu, 3);
    printf("Queue is Empty:%d\n", isLinkedEmpty(lqu));
    deLinkedQueue(&lqu, &x);
    printf("出队的元素为:%d\n", x);
    deLinkedQueue(&lqu, &x);
    printf("出队的元素为:%d\n", x);
    deLinkedQueue(&lqu, &x);
    printf("出队的元素为:%d\n", x);
}

5. Double-ended queue

A double-ended queue is a linear list in which insertion and deletion operations can be performed at both ends. A double-ended queue can be thought of as two stacks connected together at the bottom of the stack. Unlike the shared stack, the top pointers of the two stacks extend to both ends. Since the double-ended queue allows elements to be inserted and deleted at both ends, it is necessary to set up two pointers: end1 and end2, which point to the elements at both ends of the double-ended queue respectively.

Resource Allocation Map

A double-ended queue that allows insertion and deletion at one end and only deletion at the other end is called an input-restricted double-ended queue, as shown on the left side of the figure below; a double-ended queue that allows insertion and deletion at one end and only insertion at the other end The queue is called an output-limited double-ended queue, as shown on the right side of the figure below.

Resource Allocation Map

​ The basic operation of the double-ended queue can refer to the following questions:

Example: A queue allows enqueue operations at both ends of the queue, but only allows dequeue operations at one end. If elements a, b, c, d, e enter this queue in turn and then perform dequeue operations, it is impossible to get The dequeue sequence of is ( ).
A. b, a, c, d, e B. d, b, a, c, e
C. d, b, c, a, e D. e, c, b, a, d

Answer: C.

6. Summary

​ The concept and operation of the stack are relatively simple, but it often appears as an auxiliary structure in the solution of other problems, such as the level traversal of the binary tree and so on.

​ And the queue is a very widely used data structure, in our future programming, the frequency of use is very high. Be sure to be familiar with the characteristics of the team and make good use of it in solving specific problems.

For practice questions about stacks and queues, you can refer to this article .

reference:

1. C language programming foundation in data structure

2. Data structure postgraduate entrance examination outline

3. Data structure high score notes

4. Kingly data structure

5. Data structure – C language version, Yan Weimin


​ It is below the dividing line again, and this article is over. The content of this article is all organized by the blogger according to his own understanding and the postgraduate entrance examination materials. It is only for reference. If you have any questions, you can leave a message in the comment area. If you have Any mistakes, please criticize and correct.

​ This column is about data structure knowledge. If you like it, you can continue to pay attention. If this article is helpful to you, please also like, comment and pay attention.

If you have any questions, you can leave a message in the comment area.

Guess you like

Origin blog.csdn.net/qq_34666857/article/details/121455479