# Review: data structure and algorithm – 07 queue

Time：2022-5-28  xwzz.jpg

## Say something

Recently, I mentioned leaving the company and interviewed many people to find a handover person for the company. The last time I was an interviewer was two years ago;
The biggest feeling is that the environment is too impetuous. It was the same five years ago, and it is the same today. Fubao 996, middle-aged crisis, King rolling, and all kinds of negative information are entwined around;
As an individual, he is not qualified to comment on others’ career plans and instill chicken soup into others, which is more harmful. Just tell yourself: meditate, learn, introspect and move forward.

## What is a queue

To get back to business, this chapter introduces another “operation Limited” linear table data structure:queue

AndStackThe structure is the same. It only supports add and delete operations:

• Delete operation (dequeue)

The difference is that, contrary to the first in and last out of the stack, it has“First in, first out”Characteristics: Line up Png

In the figure, queuing to buy tickets is a typical queue structure. The people who line up first have the priority to buy tickets. Queue structure Png

We call the team entry operation“enqueue()”, for outbound operation“dequeue()”A simple queue operation constraint is as follows:

``````//Queue basic operation constraint interface
public interface Queue<T> {

//Join the team
boolean enqueue(T item);

//Leave the team
T dequeue();

//Is it empty
boolean isEmpty();

//Number of data in the queue
int size();

//Empty
void clear();
}``````

One satisfactionFirst in first outThe key isenqueue()anddequeue()Function, and the selection of basic containers is the same as that in the previous chapterStack structureSimilarly, you can use arrays or linked lists. Using arrays to implement queues is called:Sequential queue, using a linked list:Chain queue
For scenarios with strict resource constraints, it is recommended to use sequential queues, but there is no requirement for resource constraints. For scenarios that only need the first in last out feature, chain queues can be used.

### Sequential queue (array)

The following is the idea of implementing sequential queues with arrays. You may wish to have a look:

Sequential queue:

• 1. Define an items[] array to store data;

• 2. Define a head pointer and a tail pointer, which respectively point to the first and last subscripts of the current queue;

• 3. In enqueue(), check whether the queue is full:

• Full, return false, failed to join the team;
• If it is not full, the data is stored at the end of the queue (tail pointer position), and the tail pointer moves one bit backward;
• 4. In dequeue(), check whether the queue is empty:

• Empty: return null
• Non null: returns the queue head data (head pointer position) and moves the head pointer back one bit.

According to this idea, I pasted the implementation code below:

``````public class ArrayQueue<T> implements Queue<T> {

private static final int DEFAULT_SIZE = 10;

//Number of data in the queue
private int count;

private Object[] items;

//Maximum capacity that the current queue can store
private int maxSize;

private int head = 0, tail = 0;

public ArrayQueue() {
this(DEFAULT_SIZE);
}

public ArrayQueue(int intSize) {
items = new Object[intSize];
this.maxSize = intSize;
}

@Override
public boolean enqueue(T item) {
//Queue full, storage failed
if (tail == maxSize) return false;

//Store, end of queue subscript moves back one bit
items[tail] = item;
++tail;
++count;
return true;
}

@Override
public T dequeue() {
//Queue empty, return null
if (isEmpty()) return null;

//Take out the data and move the first subscript to the next position
--count;
return (T) item;
}

@Override
public boolean isEmpty() {
return count == 0;
}

@Override
public int size() {
return count;
}

@Override
public void clear() {
if (isEmpty()) return;
for (int i = 0; i < size(); i++) {
items[i] = null;
}
count = 0;
}

public void print() {
for (int i = head; i < tail; i++) {
System.out.print(items[i] + "\t");
}
System.out.println();
}
}``````

Test:

``````ArrayQueue<String> queue = new ArrayQueue<>(3);
queue.enqueue("1");
queue.enqueue("2");
queue.enqueue("3");
queue.enqueue("4");
queue.enqueue("5");
queue.print();
String data1 = queue.dequeue();
System Out Println ("outgoing:" + data1);
String data2 = queue.dequeue();
System Out Println ("outgoing:" + data2);
queue.print();
System Out Println ("size:" + queue. Size());

//Problem: the queue has free space but cannot add data
System.out.println(queue.enqueue("6"));
queue.print();
System Out Println ("size:" + queue. Size());``````

Output:

``````1   2   3
Outgoing: 1
Outgoing: 2
3
Size: 1

false
3
Size: 1``````

Through the test, we created a queue with a size of 3 and added 5 elements at one go. Because the queue can only hold 3 elements, the subsequent 4 and 5 elements failed; Then two elements 1 and 2 are left out of the queue, and only element 3 is left in the queue, meeting the requirements ofFirst in first outPrinciples.

However, when I tried to continue adding element 6, I failed! The current size of the queue is still 1, but we know that the total size of the queue is obviously 3, but we cannot continue to add data to the queue. Obviously, this is not the result I want. We can see the reason from the following figure: Failed to join the team Png

When we enter the queue in the first step, the tail pointer has reached the end of the queue. No matter how many elements are out of the queue in the second step, the tail pointer has not been reset. Obviously, this is the root cause of this problem.

How to solve it?
Data movement!Yes, inArray chapterAs mentioned, to insert a data into an array, you need to move the insertion position and all subsequent data back one bit; Similarly, when the first element in the queue leaves the queue, move all the elements after the first element forward by one bit and set the tail–, so as to ensure that the tail pointer always points to the actual tail element subscript in the team, rather than the tail subscript of the actual size of the queue.

According to the above idea, the problem is indeed solved. However, data movement is required every time the queue is out, which makes the time complexity of the dequeue() function change from the original o (1) – “O (n)

Is there a better plan?
From another angle, let’s take a look at enqueue() queue function. When we execute step 3, queue element 6, the queue fails because the tail pointer points to the end of the queue. However, the above figure shows that there is free space in front of the head pointer. Can we move the data?

As shown in the above figure, when the third step is executed, the tail pointer points to the end of the queue, but the head pointer is not at the head of the queue. Then move 3 to the position with the subscript 0, reset the head and tail pointer positions, and then enter the queue element 6. Modify the enqueue() function according to this idea as follows:

``````public boolean enqueue(T item) {
//Queue reached end
if (tail == maxSize) {
//Queue full, storage failed
if (head == 0) return false;

//There is free space at the head of the queue to move data
for (int i = head; i < tail; i++) {
}
//Correct the head and tail Subscripts
}

//Store, end of queue subscript moves backward one bit
items[tail] = item;
++tail;
++count;
return true;
}``````

ModifiedEnqueue() function time complexityHow much is it? The analysis is as follows:

• When the tail does not reach the tail, you can join the team directly. Time complexity: O (1)
• When the tail reaches the tail, the team leader has free space to move the data. The time complexity is O (n)
• For each queue operation, the tail may be at 0N anywhere, 0The time complexity at position n-1 is O (1), and the time complexity at position n is O (n). These n moves can be shared equally with the previous n-1 moves, so the final average time complexity is:O(1)

OK. Next, learn about the chain queue:
Chained queues are much simpler than sequential queues and do not need to worry about insufficient storage space or data movement.

Chained queue:

• 1. Define a head pointer and a tail pointer, which are used to point to the first and last nodes of the current queue;
• 2. When enqueue() is queued, only tail Next – > newnode, tail – > tail Next
``````public class LinkedQueue<T> implements Queue<T> {

private int count = 0;

@Override
public boolean enqueue(T item) {
Node<T> newNode = new Node<>(item);
} else {
tail.next = newNode;
tail = tail.next;
}
count++;
return true;
}

@Override
public T dequeue() {
if (head == null) return null;
count--;
return item;
}

@Override
public boolean isEmpty() {
return count == 0;
}

@Override
public int size() {
return count;
}

@Override
public void clear() {
}

public void print() {
while (temp != null) {
System.out.print(temp.data + "\t");
temp = temp.next;
}
System.out.println();
}

static class Node<T> {

Public t data// Store data
Public node<t> next// Next node

public Node(T data) {
this.data = data;
}

}
}``````

Test:

``````LinkedQueue<String> queue = new LinkedQueue<>();
queue.enqueue("1");
queue.enqueue("2");
queue.enqueue("3");
queue.enqueue("4");
queue.enqueue("5");

queue.print();

System Out Println ("outgoing:" + queue. Dequeue());
System Out Println ("outgoing:" + queue. Dequeue());
System Out Println ("outgoing:" + queue. Dequeue());

queue.print();

queue.enqueue("6");

queue.print();``````

Output:

``````Outgoing: 1
Outgoing: 2
Outgoing: 3
4   5
4   5   6``````

You can see that the chain queue, whether enqueue() or dequeue(), can directly access the corresponding node through the pointer, so the time complexity of the chain queue is:O(1)

### Circular queue

As mentioned earlier, it is recommended to use sequential queues in scenarios with limited memory resources. On the contrary, chain queues can be used. If you want to have the same efficient queue entry operation as the chain queue under limited resources, can such a queue be realized? Circular queue Png

As shown in the figure, we connect the array end to end:

• When joining the queue, when the data is filled to the tail and continues to be filled, the reset tail pointer points to the memory space with the subscript of 0. If the space is idle, joining the queue succeeds; otherwise, joining the queue fails when it is full;
• When leaving the queue, the actual head pointer position is calculated by the formula head = (head + 1)% maxsize.
``````/**
*Circular queue
*/
public class CircularQueue<T> implements Queue<T> {

private static final int DEFAULT_SIZE = 10;

//Number of data in the queue
private int count;

private Object[] items;

//Maximum capacity that the current queue can store
private int maxSize;

//Head points to the queue header subscript, and tail points to the tail subscript
private int head = 0, tail = 0;

public CircularQueue() {
this(DEFAULT_SIZE);
}

public CircularQueue(int intSize) {
items = new Object[intSize];
this.maxSize = intSize;
}

@Override
public boolean enqueue(T item) {
//Team full
if (count == maxSize) return false;
//Tail arrives at the end of the team,
if (tail == maxSize) tail = 0;
//Store, end of queue subscript moves backward one bit
items[tail] = item;
++tail;
++count;
return true;
}

@Override
public T dequeue() {
//Queue empty, return null
if (isEmpty()) return null;
//Take out the data and move the subscript of the team head backward by one bit
--count;
return (T) item;
}

@Override
public boolean isEmpty() {
return count == 0;
}

@Override
public int size() {
return count;
}

@Override
public void clear() {
if (isEmpty()) return;
for (int i = 0; i < size(); i++) {
items[i] = null;
}
count = 0;
}

public void print() {
for (int i = head, j = 0; j < count; i = (i + 1) % maxSize, j++) {
System.out.print(items[i] + "\t");
}
System.out.println();
}
}``````

Test:

``````CircularQueue<String> queue = new CircularQueue<>(5);
queue.enqueue("1");
queue.enqueue("2");
queue.enqueue("3");
queue.enqueue("4");
queue.enqueue("5");
queue.enqueue("6");

queue.print();

System Out Println ("outgoing:" + queue. Dequeue());
System Out Println ("outgoing:" + queue. Dequeue());

queue.print();

queue.enqueue("7");

queue.print();``````

Output:

``````1   2   3   4   5
Outgoing: 1
Outgoing: 2
3   4   5
3   4   5   7``````

Since enqueue() and dequeue() correct the tail pointer and head pointer respectively, there will be no data movement. The time complexity is:O(1).

## Long-form diagram of java reflection mechanism and its application scenarios

1. What is java reflection? In the object-oriented programming process of java, we usually need to know a Class class first, and thennew classname()way to get an object of this class. That is to say, we need to know which class we want to instantiate and which method to run when we write the code […]