[Java] was it the last time I knew how simple the stack and queue were

Then next, let me be reasonable!

Introduction

Stack, queue and linear table are all linear data structures. There is a linear relationship between each element, but they are different from the general linear structure.

The operations implemented on the stack are limited to the end of the table. The main operations are entering the stack, leaving the stack and taking the elements at the top of the stack

The operations on the queue are limited to the header and footer. The main operations are queue entry at the footer, queue exit at the header, and get the right header element at the header

1, Stack

1.1 concept

Stack operation has the characteristics of first in and last out

In life, such examples are everywhere. When using dishes, they always take them from top to bottom, and when washing dishes, they always stack them together from bottom to top. A pile of thick books. If you want to get the books pressed below, the safer way is to take the books above one by one, get the books you want, and put the books on it one by one.

Rule summary: no matter taking plates and books or putting plates and books, they are only carried out at the top, following the principle of putting in later and taking out first

This is how the stack is used. First in, last out, last in, first out. It is only allowed to insert elements (i.e. into the stack) and delete elements (out of the stack) in a fixed section. This end is called the top of the stack, and the other end is the bottom of the stack. The top of the stack will always change with insertion and deletion, and the bottom of the stack will always be fixed.

1.2 examples

1.2.1 impossible stack order

Title:
Given that the stacking sequence of a stack is mnxyz, what is the impossible stacking sequence?

A.mnxyz B.xnyzm C.nymxz D.nmyzx

Solution:

The focus of this topic is that you can also directly exit the stack after entering the stack

Option A: obviously, the five elements are put on the stack and then directly out of the stack
Option B: mnx in turn, x out of the stack, n out of the stack, y out of the stack after entering the stack, z out of the stack after entering the stack, m finally out of the stack, established
Option C: mn in turn, n out of the stack, xy in turn, y out of the stack. If the next one is out of the stack, it must be x instead of m. error

Option D: mn in turn, n out of the stack, m out of the stack, xy in turn, y out of the stack, z out of the stack after entering the stack, and x out of the stack at last. True

1.2.2 infix expression to suffix expression

There are three different notation of expressions, namely prefix, infix and suffix expression. The expression commonly used in our daily life is infix expression. The operator is in the middle of the operand, the operator of prefix expression is in front of the operand, and the operator of suffix expression is behind the operand.

For example:

Infix expression: (((2 + 3) * 4) - (6 / 2))

Prefix expression: - * + 2 3 4 / 6 2

Suffix expression: 2 3 + 4 * 6 2 /-

For people, the form of infix expression is easier to calculate. There is no way to see what is written at one time

For the computer, the calculation of prefix and suffix expressions is simpler. Therefore, when calculating expressions, the computer will convert infix expressions into prefix or suffix expressions

Take infix expression to suffix expression as an example to show the simplest conversion method:

1. Add () according to the priority of the operator
2. Move the operator after the corresponding bracket in turn (before the bracket if it is converted to a prefix expression)
3. Remove the parentheses to get the suffix expression

Take the expression ((2 + 3) * 4) as an example

Illustration:

How suffix expressions are evaluated:

1. If the suffix expression is a number, it is put on the stack in turn
2. If you encounter an operator, pop up a number from the stack and put it on the right side of the operator, and then pop up a number and put it on the left side of the operator
3. After calculation, put the calculation results on the stack
4. Cycle back and forth until there are no numbers in the stack, and the whole calculation process is completed

1.3 self realization

The stack can be realized in the form of sequential table or linked list. Relatively speaking, the implementation of sequential table is more convenient and simple. Here, the stack is realized in the form of sequential table.

The sequential storage structure of the stack refers to the use of a group of storage units with continuous addresses to store data elements from the bottom of the stack to the top of the stack in turn. The stack stored in the sequential storage mode is called the sequential stack. Here, the class MyStack that implements this stack is called the sequential stack class

Here, a one-dimensional array int[] elem is used to store the data elements in the stack and set the appropriate initial length; Use the variable usedSized to record the number of data elements in the stack. If you want to delete an element (out of the stack), reduce it by one. If you want to enter the stack, increase it by one. If you want to empty the stack, you can make it 0

Implementation method:

• public MyStack()

Initializes the length of the array

• public boolean isFull()

When it is found that the number of elements in the stack is equal to the length of the array, it means that the stack is full, return true, otherwise return false

• public void push(int val)

Push the data element val into the stack. If the stack is full, expand the capacity of the array that implements the stack, and then place the data element where the array subscript is usedSized, and increase the size of the array by one

• public boolean empty()

Judge whether the stack is empty. When the usedSized size is found to be 0, it returns true; otherwise, it returns false

• public int peek()

If the stack is not empty, the data element at the top of the stack is returned; If it is empty, an exception will be reported, indicating that the stack is empty

• public int pop()

If the stack is not empty and the usedSized size is reduced by one, the data element at the top of the stack is deleted and returned; If it is empty, an exception will be reported, indicating that the stack is empty

ðŸ“‘ Code example:

```import java.util.Arrays;
public class MyStack {
public int[] elem;
public int usedSized;
//initialization
public MyStack() {
this.elem = new int[100];
}
//Determine whether the stack is full
public boolean isFull() {
return (this.usedSized == this.elem.length);
}
//Push
public void push(int val) {
if (isFull()){
this.elem = Arrays.copyOf(this.elem,this.elem.length*2);
}
this.elem[this.usedSized] = val;
this.usedSized++;
}
//Determine whether the stack is empty
public boolean empty() {
return this.usedSized == 0;
}
//Get stack top element
public int peek() throws RuntimeException{
if (empty()){
throw new RuntimeException("The stack is empty");
}
return this.elem[this.usedSized-1];
}
//Out of stack
public int pop() throws RuntimeException{
if (empty()){
throw new RuntimeException("The stack is empty");
}
this.usedSized--;
return this.elem[this.usedSized - 1];
}
}
```

2, Queue

1.1 concept

Queue operation has the characteristics of first in first out

Like queuing in life, it pays attention to first come, first serve and first go. In queuing events, new members join the end of the team, and the members who leave each time come from the head of the team, that is, the end of the team enters the team and the head of the team leaves the team.

This is how queues are used, first in, first out, last in, then out. The queue is only limited to inserting at one end, which is called the end of the queue. It is only limited to deleting at the other end, and the other end is called the head of the queue. The insertion operation is called in the queue, and the deletion operation is called out of the queue. With the insertion and deletion, the queue head and tail change all the time.

a1 is the team head element and an is the team tail element. The elements in the queue are queued in the order of a1, a2, a3,..., an-1 and an. According to the concept of queue, if the queue entry operation is to be performed, the queued element is an+1, which becomes the end of the queue. If the queue exit operation is performed, the queued element is a1, and the queue head is a2.

1.2 examples

1.2.1 number of students unable to eat lunch

Title:

The school buffet lunch offers round and square sandwiches, represented by the numbers 0 and 1, respectively. All the students stand in a queue. Each student likes either round or square.
The number of sandwiches in the restaurant is the same as that of students. All sandwiches are placed in a stack, each round:

If the student at the front of the queue likes the sandwich at the top of the stack, he will take it and leave the queue.
Otherwise, the student will give up the sandwich and go back to the end of the queue.
This process will continue until all the students in the queue don't like the sandwich at the top of the stack.

Here are two integer arrays, students and sandwiches, where sandwiches[i] is the type of the ith sandwich in the stack (i = 0 is the top of the stack), and students[j] is the j-th student's preference for sandwiches in the initial queue (j = 0 is the beginning of the queue). Please return the number of students who cannot have lunch.

Solution:

If this problem is solved with the idea of queue, it should be like this...

Step 1: first, judge whether the student array and sandwich array are empty to enhance the robustness of the code

Step 2: put the students' preferences for sandwiches into a queue

Step 3: enter a cycle. The condition is that the student queue is not empty and the length of the sandwich array cannot exceed (the number of sandwiches in this topic is the same as the number of students, so this condition will be true, so this condition is for different numbers)

Step 4: make a cycle judgment in the above cycle. If the preferences match successfully during the round, send the students at the head of the team away, and the j subscript of the sandwich array goes back one grid. If the elements of the j subscript of the student team head and the sandwich array are different, send them away from the head of the team and to the end of the team, and all members in the queue take turns, No one took the sandwich, which means that the size of the queue is the number of students without food

Step 5: after the cycle is completed, there is still no return. Under the condition of this question, the queue must be empty. If the number of sandwiches is different from the number of students, it may also be because the number of sandwiches is small, and the size of the queue is the number of students without food

Illustration example:

ðŸ“‘ Code example:

```class Solution {
public int countStudents(int[] students, int[] sandwiches) {
//Judge whether the student array and sandwich array are empty
if (students == null || students.length == 0) return 0;
if (sandwiches == null || sandwiches.length == 0) return students.length;
//Put the students' preferences for sandwiches into a queue
for (int i = 0; i < students.length; i++) {
}
int j = 0;
while (!queue1.isEmpty() && j < sandwiches.length) {
int i = 0;
for (; i < queue1.size(); i++) {
//The student team head is different from the j subscript element of the sandwich array, so they send it away from the head of the team and to the end of the team
if (queue1.peek() != sandwiches[j]) {
}else {
//Successful preference matching
break;
}
}
//All the members of the queue took turns. At this time, the size of the queue is the number of students without food
if (i == queue1.size()) {
return queue1.size();
}
//If the preference matching is successful, the students at the head of the team will be sent away, and the j subscript of the sandwich array will go back one grid
queue1.poll();
j++;
}
//Returns the size of the queue
return queue1.size();
}
}
```

1.3 self realization

Due to the characteristics of queue first in first out, if you want to use an ordinary one-dimensional array to implement the queue, when you want to insert elements at the end of the queue, the time complexity is O(1), but when you delete elements at the head of the queue, because the elements with subscript 0 are removed, it means that the following elements must move forward one grid collectively, and the time complexity is O(N)

Therefore, it is more advantageous to adopt the chain storage structure than the sequential storage structure. Here, we will use the linked list to realize the queue. We can use the two-way linked list or the single linked list. Here, we will use the single linked list to realize a queue, define a front node to record the head of the linked list, that is, the head of the queue, and define a rear node to record the tail of the linked list, that is, the tail of the queue

The operation of chained queue is actually a special case of inserting and deleting a single linked list. The queueing operation is equivalent to inserting a data element from the tail of the chain, and the queueing operation is equivalent to deleting a data element from the head of the chain. Both the queueing operation and the queueing operation can be realized by modifying the direction of the front node and the rear node.

Implementation legend:

Implementation method:

• public void offer(int val)

Insert a new tail element val into the chain queue.

Step 1: generate a new node newNode with element value val

Step 2: judge whether the chain queue is empty. If it is empty, make the head node front point to the new node. If it is not empty, make the reference field of the tail node rear point to the new node

Step 3: make the tail node point to the new node

Step 4: the number of elements in the chain queue usedSize plus one

• public int poll()

If the chain queue is empty, an exception of "empty queue" will be thrown; If it is not empty, the queue header element is taken from the queue and returned

Step 1: judge whether the queue is empty and throw an exception if it is empty

Step 2: define the variable ret to record the value of the data field of the queue head element at this time

Step 3: if there is only one node at this time, set both the head node and the tail node to null. If there is more than one node, make the head node front point to the next element it points to, that is, delete the node of the team head

Step 4: the number of elements in the chain queue usedSize minus one

• public int peek()

If the chain queue is empty, an exception of "empty queue" will be thrown; If it is not empty, the queue header element is returned from the queue

Step 1: judge whether the queue is empty and throw an exception if it is empty

Step 2: return the value of the data field of the team head element pointed to by the head node front at this time

• public boolean isEmpty()

Judge whether the chain queue is empty. If it is empty, usedSize is 0

• public int size()

Returns the length of the chain queue

ðŸ“‘ Code example:

```class Node {
public int data;
public Node next;

public Node(int data) {
this.data = data;
}
}
//When not initialized, the default front and rear point to null, and the usedSize is 0
private Node front;
private Node rear;
private int usedSize;
//Queue
public void offer(int val) {
Node newNode = new Node(val);
if (isEmpty()){
this.front = newNode;
}else {
this.rear.next = newNode;
}
this.rear = newNode;
this.usedSize++;
}
//Out of queue
public int poll() throws RuntimeException{
//Determine whether the queue is empty
if (isEmpty()) {
throw new RuntimeException("Queue is empty");
}
int ret = this.front.data;
//Judge whether it is a node
if (this.front.next == null) {
this.front = null;
this.rear = null;
}else {
this.front = this.front.next;
}
this.usedSize--;
return ret;
}
public int peek() throws RuntimeException{
//Determine whether the queue is empty
if (isEmpty()) {
throw new RuntimeException("Queue is empty");
}
return this.front.data;
}
//Determine whether the chain queue is empty
public boolean isEmpty() {
return this.usedSize == 0;
}
//Returns the length of the chain queue
public int size() {
return this.usedSize;
}
}
```

1.4 Dual Ended queue (deque)

As the name suggests, it refers to a queue that allows both ends to enter and exit the queue, which means that elements can exit and join the team from the head of the team, or exit and join the team from the tail of the team.

In fact, after the implementation of the above queue, the implementation method of the double ended queue is basically the same. For convenience, the idea of two-way linked list is used to realize the double ended queue. I won't say much here. Go to the code!

ðŸ“‘ Code example:

```class Node {
public int data;
public Node next;
public Node prev;

public Node(int data) {
this.data = data;
}
}
class MyDeque {
public Node rear;//Record the end of the queue
public int usedSized;//Number of elements in the queue
public int capacity;//Capacity size of the queue
//Initialize the capacity size of the queue
public MyDeque(int k) {
this.capacity = k;
}
//Add an element to the header of the double ended queue, and return true if the operation is successful
public boolean insertFront(int value) {
Node newNode = new Node(value);
if (isFull()) {
return false;
}
if (!isEmpty()) {
}else {
this.rear = newNode;
}
this.usedSized++;
return true;
}
//Add an element to the end of the double ended queue, and return true if the operation is successful
public boolean insertLast(int value) {
Node newNode = new Node(value);
if (isFull()) {
return false;
}
if (!isEmpty()) {
this.rear.next = newNode;
newNode.prev = this.rear;
}else {
}
this.rear = newNode;
this.usedSized++;
return true;
}
//Delete an element from the header of the double ended queue, and return true if the operation is successful
public boolean deleteFront() {
if (isEmpty()) {
return false;
}
//If there is only one node in the double ended queue
this.rear = null;
}else {
}
this.usedSized--;
return true;
}
//Delete an element from the tail of the double ended queue, and return true if the operation is successful
public boolean deleteLast() {
if (isEmpty()) {
return false;
}
//If there is only one node in the double ended queue
this.rear = null;
}else {
this.rear = this.rear.prev;
}
this.usedSized--;
return true;

}
//Get an element from the header of the double ended queue. If the double ended queue is empty, return - 1
public int getFront() {
if (isEmpty()) return -1;
}
//Get an element from the end of the double ended queue. If the double ended queue is empty, return - 1
public int getRear() {
if (isEmpty()) return -1;
return this.rear.data;
}
//Check whether the double ended queue is empty. The standard is that the number of data elements in the double ended queue is equal to 0
public boolean isEmpty() {
return this.usedSized == 0;
}
//Check whether the double ended queue is full. The standard is that the number of data elements in the double ended queue is equal to the queue capacity
public boolean isFull() {
return this.usedSized == this.capacity;
}
}
```

3, Stacks and queues in Java

Stack and queue can be used directly in Java. The specific methods are as follows

3.1 stack in Java

methodeffect
public E push(E item)Push
public synchronized E peek()Out of stack
public synchronized E pop()View stack top element
public boolean empty()Determine whether the stack is empty

ðŸ“‘ Code example:

```import java.util.Stack;
public class TestDemo {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
stack.push(2);
stack.push(4);
System.out.println(stack.peek());//4
System.out.println(stack.pop());//4
System.out.println(stack.empty());//false
}
}
```

3.2 queues in Java

effectMode 1Mode II
Out of queueE remove()E poll()
View team leader elementE element()E peek()

ðŸ“‘ Code example:

```import java.util.LinkedList;
import java.util.Queue;
public class TestDemo {
public static void main(String[] args) {
queue.offer(5);
System.out.println(queue.element());//4
System.out.println(queue.peek());//4
System.out.println(queue.remove());//4
System.out.println(queue.poll());//5
System.out.println(queue.isEmpty());//true
}
}
```

explain:

Use LinkedList to implement the queue. Both mode 1 and mode 2 can implement the required methods. The difference is that when an error is encountered, mode 1 will throw an exception, and mode 2 will return a special value

3.3 double ended queue in Java

methodMode 1Mode II
Out of queueremoveFirst() removeLast()pollFirst() pollLast()
View elementgetFirst() getLast()peekFirst() peekLast()

ðŸ“‘ Code example:

```import java.util.Deque;
public class TestDemo {
public static void main(String[] args) {
deQueue.offerFirst(4);
deQueue.offerLast(5);
System.out.println(deQueue.removeFirst());//4
System.out.println(deQueue.peekLast());//5
System.out.println(deQueue.pollLast());//5
System.out.println(deQueue.getFirst());//2
System.out.println(deQueue.isEmpty());//false
}
}
```

explain:

Use LinkedList to implement the queue. Both mode 1 and mode 2 can implement the required methods. The difference is that when an error is encountered, mode 1 will throw an exception, and mode 2 will return a special value

Over!

Posted on Sat, 23 Oct 2021 07:01:40 -0400 by Ludo Lambrechts