# 1. Basic knowledge of queue

### 1.1 concept and characteristics

Queue concept:

Queue: a special linear table that only allows data insertion at one end and data deletion at the other end. In Java, queue is an interface inherited from Collection, and the bottom layer is realized through linked list;

The end of the inserted data is called the tail of the queue, and the end of the deleted data is called the header.

As shown in the figure below:

Queue characteristics:

The queue follows the first in first out principle (First In First Out);

Great God parable: eat in and pull out

### 1.2 use of queues

Common methods:

- boolean offer(E e): queue element E
- E poll(): out of queue
- E peek(): get the queue header element
- int size(): get the number of valid elements in the queue
- boolean isEmpty(): check whether the queue is empty

package day20211018; import java.util.LinkedList; import java.util.Queue; public class TestQueue { //Test queue public static void main(String[] args) { Queue q=new LinkedList(); //Queued: 1 2 3 4 q.offer(1); q.offer(2); q.offer(3); q.offer(4); System.out.println(q); //[1, 2, 3, 4] //Get queue header element System.out.println(q.peek()); //1 //Gets the number of elements in the queue System.out.println(q.size()); //4 //First 2 elements out of the team q.poll(); q.poll(); System.out.println(q); //[3, 4] //Determine whether the queue is empty if(q.isEmpty()) { System.out.println("The queue is empty"); }else{ System.out.println("Team is not empty"); } } }

# 2. Simulation implementation queue

package day20211023; //Simulated implementation Queue -- Queue public class Queue <E>{ public static class ListNode<E>{ E value; ListNode<E> next; ListNode<E> prev; public ListNode(E val){ this.value = val; } } ListNode<E> first; //The tag represents the team head element ListNode<E> last; // Tag tail element int size=0; //Number of valid elements in the queue //Queue -- offer public boolean offer(E e){ ListNode<E> newNode=new ListNode<>(e); if(first==null){ //Queue is empty first=newNode; //last=newNode; }else{ //Queue is not empty last.next=newNode; //last=newNode; } last=newNode; size++; return true; } //Out of queue - poll //Essence: delete team head element public E poll() { if(0 == size){ return null; } ListNode<E> delNode = first; first = first.next; if(null == first){ last = null; } size--; return delNode.value; } //Get queue header element public E peek() { if (first == null) { //Description there are no elements in the queue return null; } return first.value; } //Get the number of valid elements public int size(){ return size; } // Air judgment public boolean isEmpty(){ return first==null; } public static void main(String[] args) { Queue<Integer> q=new Queue<>(); //Test queued 1 2 3 4 5 q.offer(1); q.offer(2); q.offer(3); q.offer(4); q.offer(5); System.out.println(q.size()); //5 System.out.println(q.peek()); //1 //Test out queue q.poll(); q.poll(); q.poll(); System.out.println(q.size()); //2 System.out.println(q.peek()); //4 //Test blank if(q.isEmpty()){ System.out.println("Queue is empty"); }else{ System.out.println("Queue is not empty"); } } }

reflection:

In Java, the queue is implemented by linked list. If continuous space is adopted, can the time complexity of all operations of the queue be O(1)?

The analysis is as follows:

It is assumed that the operations of entering the queue, leaving the queue and obtaining the queue header elements are realized with the help of a continuous space of the array;

As shown in the following figure: enter the queue: 1 2 3 4 5 6 these six elements can be directly inserted into the tail, and the time complexity is O(1);

Out of queue: because the queue has the characteristics of first in first out, out of queue can be realized only when this element becomes the queue head element;

Out of queue mode 1:

Keep the front still and move the next five elements forward one position as a whole; Move the rear forward one position;

Note: Although this can realize out of queue, when there are N elements, it needs to be moved N-1 times, so the time complexity is O(N), which does not meet the requirements;

As shown in the figure below:

Then, how to ensure that the time complexity of all operations of the queue is O(1)?

Mode 2:

When leaving the queue, you can move the front one step back;

Reason: every time the front marks the queue head element, when the front moves back, it is equivalent to moving the previous element out of the queue;

Moreover, it ensures that the time complexity of outgoing queue is O(1), but this method will lead to false overflow.

False overflow: when you want to insert data into this space again, because the rear has pointed to the end of the space, you cannot insert it. But in fact, the first three elements have been out of the queue. There is room left in this part, but it can't be used. This phenomenon is called false overflow of queue;

Aiming at the false overflow problem caused by the use of continuous space, a circular queue is proposed

# 3. Circular queue

Circular queue: it is to wrap the last position of the queue storage space back to the first position to form a logical ring space, so as to realize the circular use of the queue. Circular queue is also a linear data structure, and its operation performance is based on the FIFO (first in, first out) principle; As shown in the figure below:

As shown in the ring queue diagram above:

When entering the queue:

Put the element at the end of the rear line, and then move the rear one step back;

When leaving the queue: move front one step back;

When another element is inserted at position 5 in the figure above, the rear points to the position of the front. At this time, how to judge whether the queue is empty or full?

There are three ways to judge whether the circular queue is empty or full * *:

- Use count to count

When count is 0, the circular queue is empty;

When count is arr.length, the circular queue is full;

- Store one element less

When front equals rear, the queue is empty;

When rear plus 1 equals rear, the queue is full

Note: when the elements in the queue are stored in the last position, inserting the elements will return to the starting position, so the judgment conditions when the queue is full are:

(rear+1)% arr.length==front

- Set flag bit

In the initial state, set the flag to false

When entering the queue, rear moves to the next position, and flag=true;

When leaving the queue: front moves to the next position, and flag=false;

When front equals rear & & Flag equals false, the queue is empty;

When front equals rear & & Flag equals true, the queue is full;

How to implement a circular queue?

Circular queue implementation code:

class MyCircularQueue { int[] array; int front=0; //Tag header element int rear=0; //Tag tail element int count=0; //Determine whether the queue is full or empty int N; //Length of queue public MyCircularQueue(int k) { array=new int[k]; N=k; } //Queue public boolean enQueue(int value) { if(isFull()){ return false; } array[rear]=value; rear++; if(rear==N){ rear=0; } count++; return true; } //Out of queue public boolean deQueue() { if(isEmpty()){ return false; } front++; front %= N; count--; return true; } //Get queue header element public int Front() { if(isEmpty()){ return -1; } return array[front]; } //Get tail element public int Rear() { if(isEmpty()){ return -1; } return array[((rear-1)+N)%N]; } public boolean isEmpty() { return 0==count; } public boolean isFull() { return count==array.length; } }

# 4. Double ended queue

Deque refers to a queue that allows both ends to enter and leave the queue. The bottom layer is also realized through LinkedList; The structure diagram in the collection framework is shown in the following figure:

# Common written questions

(very important)

Note: for the following three questions, click the blue link to view the original question!!!

Question 1: queue implementation stack

Problem Description: please use only two queues to implement a last in first out (LIFO) stack, and support all four operations of the ordinary stack (push, top, pop and empty).

Implement MyStack class:

- void push(int x) pushes element X to the top of the stack.
- int pop() removes and returns the top of stack element.
- int top() returns the stack top element.
- boolean empty() returns true if the stack is empty; Otherwise, false is returned

Problem solving ideas:

Two queues q1 and q2 are used. q1 is used to store elements and q2 is used as an auxiliary queue for stacking;

When entering the stack: first queue the elements into q2, then queue all the elements of q1 into q2, and then swap the elements in the two queues. Then, the front-end elements and back-end elements of q1 are the top and bottom elements of the stack;

Since each stack entry operation ensures that the front-end element of q1 is the top element of the stack, the stack exit operation only needs to remove the front-end element of q1 and return.

Get stack top element: just get the front-end element of q1 and return it;

Judge whether the stack is empty: you only need to check whether q1 is empty;

class MyStack { //Define two queues Q1 and Q2, one for storing elements and one for auxiliary queues Queue<Integer> q1=new LinkedList<>(); Queue<Integer> q2=new LinkedList<>(); public MyStack() { } //Push public void push(int x) { q2.offer(x); while (!q1.isEmpty()) { q2.offer(q1.poll()); } Queue<Integer> temp = q1; q1 = q2; q2 = temp; } //Out of stack public int pop() { return q1.poll(); } //Get stack top element public int top() { return q1.peek(); } public boolean empty() { return q1.isEmpty(); } }

Question 2: using stack to realize queue

Problem Description: please use only two stacks to implement the first in first out queue. The queue should support all operations supported by the general queue (push, pop, peek, empty):

Implement MyQueue class:

- void push(int x) pushes element X to the end of the queue
- int pop() removes the element from the beginning of the queue and returns it
- int peek() returns the element at the beginning of the queue
- boolean empty() returns true if the queue is empty; Otherwise, false is returned

Problem solving ideas:

Two stacks s1 and s2 are used. s1 is used to simulate the incoming queue and s2 is used to simulate the outgoing queue;

When queuing: directly put elements into s1;

When leaving the queue: if s2 is empty, import all elements in s1 into s2 and delete the elements at the top of s2 stack;

Get the team head element: if s2 is empty, import all elements in s1 into s2 and return the s2 stack top element;

Code implementation:

class MyQueue { Stack<Integer> s1=new Stack<>(); Stack<Integer> s2=new Stack<>(); public MyQueue() { } //Queue public void push(int x) { s1.push(x); } //Out of queue public int pop() { if(s2.empty()){ //Import all elements from s1 into s2 while(s1.size()>0){ s2.push(s1.pop()); } } return s2.pop(); } public int peek() { if(s2.empty()){ while(s1.size()>0){ s2.push(s1.pop()); } } return s2.peek(); } public boolean empty() { return s1.isEmpty() && s2.isEmpty(); } }

Question 3: implement a minimum stack

Problem Description: design a stack that supports push, pop and top operations and can retrieve the smallest element in a constant time.

- push(x) -- push element x onto the stack
- pop() -- delete the element at the top of the stack.
- top() -- get the stack top element.
- getMin() -- retrieves the smallest element in the stack.

Problem solving ideas:

When stacking:

When S2 is not empty, put an element in S1 and S2 respectively;

If S2 is not empty, val is compared with the top element of S2. When val is less than or equal to the top element of S2, val is placed in one of S1 and S2. When val is greater than the top element of S2, val is placed in S1;

When exiting the stack:

When S1 and S2 stack top elements are equal, S2 is out of the stack;

S1 stack one element every time;

The stack top element is in S1

The minimum value is in S2

class MinStack { Stack<Integer> s1=new Stack<>(); Stack<Integer> s2=new Stack<>(); public MinStack() { } //Push public void push(int val) { if(s2.empty() || val<=s2.peek()){ s2.push(val); } s1.push(val); } //Out of stack public void pop() { if(s1.peek().equals(s2.peek())){ s2.pop(); } s1.pop(); } public int top() { return s1.peek(); } public int getMin() { return s2.peek(); } }