preface
The stack
concept
What is a stack?
** stack ** : is a special linear table that can only be operated on one end
Push: The operation of adding elements to the stack, commonly called push
The operation of removing an element from the stack, usually called pop.
Note: the term “stack” is different from the term “stack space” in memory
The structure of the stack
Compared with arrays and linked lists, stacks are linear data structures that store the same types of data, but with more limitations. For example: Only one end of the stack is open (the top of the stack), and all data operations are performed on this end. Due to this feature, there is a so-called “Last In First Out (LIFO)” feature. The other three sides are closed, so all elements In the stack are unknown except the top element. The stack also can’t do random access.
Illustrated stack structure:
Last in first out:
The design of the stack
In fact, in addition to the three sides of the stack closed, the other is the same as the linear data structure I have written before, so the internal implementation of the stack can be directly implemented by using the data structure I have learned before, such as DynamicArray DynamicArray, LinkedList. DynamicArray LinkedList DynamicArray LinkedList DynamicArray LinkedList
However, the Stack class we write is not directly inherited from these classes, because this will expose some original methods of DynamicArray, LinkedList, such as random access, random insert, delete, etc., which will make the Stack lose its characteristics. To solve this problem, use the composite pattern to draw the class diagram:
Stack interface design
1. Attributes:
private List<E> list;
Implement class design stack using linear tables based on the List interface
2. Interface method:
int size();
Check the number of current stack elementsboolean isEmpty();
Check whether the stack is emptypublic void push(E element);
— Push, add elementspublic E pop();
Remove the tail element from the stackpublic E top();
Get the top element of the stackvoid clear();
Clear stack elements
After the design is completed, it is the specific method encoding implementation, because it is the stack of DynamicArray DynamicArray and LinkedList LinkedList. All the calls are encapsulated methods, so I won’t go into details here
coded
public class Stack<E> extends DynamicArray<E>{
// Implement stack with dynamic array
private List<E> list = new DynamicArray<>();
// Use linked lists to implement stacks
//private List<E> list = new DynamicArray<>();
/** * check stack elements *@return* /
public int size(a) {
return list.size();
}
/** * Check whether the stack is empty *@return* /
public boolean isEmpty(a) {
return list.isEmpty();
}
/** * add element *@param element
*/
public void push(E element){
list.add(element);
}
/** * remove the tail element */
public E pop(a){
return list.remove(list.size() - 1);
}
/** * get the top element *@return* /
public E top(a){
return list.get(list.size() - 1);
}
/** * empties the stack element */
public void clear(a) { list.clear(); }}Copy the code
summary
The application of the stack
1, double stack browser forward and backward
2. Undo and Redo functions
The queue
concept
What is a queue?
Queue: Unlike previous stacks, which can only operate on elements at the top of the stack, queues can operate on elements at both ends. Queues are also special linear tables
Queue: You can only add elements from rear, usually called enQueue
Queue out: Only elements can be removed from the front of the queue, usually called a deQueue
Queue structure
Compared with arrays, linked lists, and stacks, queues are linear data structures that store the same type of data, except that queues are less restrictive than stacks, but more restrictive than arrays and linked lists. For example: The queue can only add data at the end of the queue, and the queue head removes elements. Based on this feature, with the so-called “First In First Out principle, First In First Out, FIFO”** characteristics, the other two sides are closed In structural design, so In addition to the queue head element, other elements In the queue are unknown. Of course, the element at the end of the queue is also visible, but we usually only add elements at the end of the queue, so we don’t open this method, and the queue doesn’t do random access.
Figure out the queue structure:
Queue design
Queue and array, LinkedList and stack are all linear table structures, so there is no need to do some repetitive operations. DynamicArray and LinkedList written before can be implemented, and queue can also be implemented using stack. But here we use Both_LinkedList.
Wrote in the previous – list (Java implementation) is talked about, the head of the two-way linked list node and end node is first and the last pointer to, this to queue at the team head, elements of the operation is very convenient, is, of course, using dynamic array or also can singly linked list, just behind the team head removing elements makes an array element node moves forward, In a unidirectional list, the pointer head is traversed to the tail node when the element is added to the end of the queue. Both of these add complexity, so bidirectional lists are better
Again, but we’re not going to write a Queue that inherits these classes directly, we’re going to do it as a combination, so let’s draw the class diagram
Interface design for queues
1. Attributes:
private List<E> list;
Implement class design queues using linear tables based on the List interface
2. Interface method:
int size();
View the number of current queue elementsboolean isEmpty();
— Checks whether the queue is emptypublic void enQueue(E element);
Join the team and add elementspublic E deQueue();
— Exit the queue and delete the header elementpublic E front();
Add the fetch header elementvoid clear();
Clear the queue element
After the completion of the design, is the specific method encoding implementation, because it is the use of bidirectional linked list Both_LinkedList to achieve the queue, call all encapsulated methods, not detailed here
coded
Bidirectional list implementation queue:
public class Queue<E> {
// Implement the queue using the method encapsulated in the bidirectional list
private List<E> list = new Both_LinkedList<>();
/** * get the number of queue elements *@return* /
public int size(a) {
return list.size();
}
/** * Check whether the current queue is empty *@return* /
public boolean isEmpty(a) {
return list.isEmpty();
}
/** * add element * from the end of the queue@param element
*/
public void enQueue(E element) {
list.add(element);
}
/** * remove element from team head *@return* /
public E deQueue(a) {
return list.remove(0);
}
/** * get the header element *@return* /
public E front(a) {
return list.get(0);
}
/** * Empties the queue element */
public void clear(a) { list.clear(); }}Copy the code
Dual stack implementation queue:
public class QueueByStack<E> {
// Define two stacks, inStack for the end of the queue and outStack for the end of the queue
private Stack<E> inStack,outStack;
// Use the constructor to initialize
public QueueByStack(a) {
this.inStack = new Stack<>();
this.outStack = new Stack<>();
}
/** * get the number of queue elements *@return* /
public int size(a) {
return inStack.size() + outStack.size();
}
/** * Check whether the current queue is empty *@return* /
public boolean isEmpty(a) {
return inStack.isEmpty() && outStack.isEmpty();
}
/** * add element * from the end of the queue@param element
*/
public void enQueue(E element) {
inStack.push(element);
}
/** * add element * from team head@return* /
public E deQueue(a) {
checkOutStack();
return outStack.pop();
}
/** * get the header element *@return* /
public E front(a) {
checkOutStack();
return outStack.top();
}
/** * empties the stack element */
public void clear(a) {
inStack.clear();
outStack.clear();
}
/** * Check if outStack is empty, if not, wait to be queued * if it is empty, and inStack is not empty, push the inStack element off the stack, into outStack, and prepare to be queued */
private void checkOutStack(a) {
if (outStack.isEmpty()) {
while(! inStack.isEmpty()) { outStack.push(inStack.pop()); }}}}Copy the code
deque
concept
Dual-end queue: a queue that can be added or deleted at both ends
Structure diagram:
design
There is no difference in the implementation relationship between a double-ended Queue Deque and Queue, which is also based on the bidirectional linked list Both_LinkedList and implemented in the combined mode
Interface design of bidirectional queue
1. Attributes:
private List<E> list;
Implement class design queues using linear tables based on the List interface
2. Interface method:
int size();
View the number of current queue elementsboolean isEmpty();
— Checks whether the queue is emptypublic void enQueueRear(E element);
Join the team, from the back of the linepublic E deQueueRear();
Get out, get out of the back of the linepublic void enQueueFront(E element);
Join the team, join the team from the headpublic E enQueueFront();
Get out of the team, get out of the teampublic E front();
Add the fetch header elementpublic E rear();
Add the fetch element to the end of the queuevoid clear();
Clear the queue element
coding
public class Deque<E> {
// Implement the queue using the method encapsulated in the bidirectional list
private List<E> list = new Both_LinkedList<>();
/** * get the number of queue elements *@return* /
public int size(a) {
return list.size();
}
/** * Check whether the current queue is empty *@return* /
public boolean isEmpty(a) {
return list.isEmpty();
}
/** * from the back of the line *@param element
*/
public void enQueueRear(E element) {
list.add(element);
}
/** ** from the end of the line *@return* /
public E deQueueRear(a) {
return list.remove(list.size() - 1);
}
/** * join the team from the head *@param element
*/
public void enQueueFront(E element) {
list.add(0, element);
}
/** ** out of the team, from the head *@return* /
public E deQueueFront(a) {
return list.remove(0);
}
/** * get the header element *@return* /
public E front(a) {
return list.get(0);
}
/** * get the last element *@return* /
public E rear(a) {
return list.get(list.size() - 1);
}
/** * Empties the queue element */
public void clear(a) { list.clear(); }}Copy the code
Circular queue
Circular queue
Concept:
Circular queue: An array implemented and optimized queue
Illustrated structure:
Design:
Circular queue is also called circular queue, are implemented based on Java array, using the front is the position of the pointer to a head, on the design, not after removing elements as an array, move forward elements covered, but the value empty, front, back remove elements in such a mechanism, position, after deleting when front behind pointer position is full, The new element can fill in the space just deleted, acting as a ring
Cyclic interface design
1. Attributes:
private int front;
— Loop queue head pointerprivate int size;
— Number of queue elementsprivate E[] elements;
Use sequential structured array storageprivate static final int DEFAULT_CAPACITY = 10;
— The default initialization value of the array
2. Interface method:
int size();
View the number of current queue elementsboolean isEmpty();
— Checks whether the queue is emptypublic void enQueue(E element);
Join the team, from the back of the linepublic E deQueue();
— Exit the queue and delete the header elementpublic E front();
Add the fetch header elementvoid clear();
Clear the queue elementprivate void ensureCapacity(int capacity)
– Ensure that the capacity is sufficient. If not, expand the capacityprivate int index(int index);
Index mapping function that returns the real array subscript
1. Out of line operation
2. Team entry operation
3. Rejoin the team
4. Attention points:
(1) team
(2) team
(3) out of the team
(4) capacity
Code:
public class CircleQueue<E> {
// Default initialization value for array
private static final int DEFAULT_CAPACITY = 10;
// loop queue head pointer
private int front;
// Number of queue elements
private int size;
// Use sequential arrays for storage
private E[] elements;
The /** * constructor initializes the array */
public CircleQueue(a) {
elements = (E[]) new Object[DEFAULT_CAPACITY];
}
/** * gets the number of queue elements *@return* /
public int size(a){
return size;
}
/** * Check whether the queue is empty *@return* /
public boolean isEmpty(a){
return size == 0;
}
/** * add element * from the end of the queue@param element
*/
public void enQueue(E element) {
ensureCapacity(size + 1);
//elements[(front + size) % elements.length] = element;
// Call the wrapper function
elements[index(size)] = element;
size++;
}
/** * remove element from team head *@return* /
public E deQueue(a) {
E element = elements[front];
elements[front] = null;
//front = (front + 1) % elements.length;
// Call the wrapper function
front = index(1);
size--;
return element;
}
/** * get the header element *@return* /
public E front(a){
return elements[front];
}
/** * Empties the queue element */
public void clear(a) {
for (int i = 0; i < size; i++) {
//elements[(i + front) % elements.length] = null;
// Call the wrapper function
elements[index(i)] = null;
}
front = 0;
size = 0;
}
/** * Ensure that the capacity of capacity is sufficient@param capacity
*/
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if (oldCapacity >= capacity) return;
// The new capacity is 1.5 times the old capacity
int newCapacity = oldCapacity + (oldCapacity >> 1);
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
//newElements[i] = elements[(i + front) % elements.length];
// Call the wrapper function
newElements[i] = elements[index(i)];
}
elements = newElements;
/ / reset the front
front = 0;
}
/** * index mapping function that returns the real array subscript *@param index
* @return* /
private int index(int index){
return (front + index) % elements.length;
}
@Override
public String toString(a) {
StringBuilder string = new StringBuilder();
string.append("capcacity=").append(elements.length)
.append(" size=").append(size)
.append(" front=").append(front)
.append("[");
for (int i = 0; i < elements.length; i++) {
if(i ! =0) {
string.append(",");
}
string.append(elements[i]);
}
string.append("]");
returnstring.toString(); }}Copy the code
Loop double – ended queue
Concept:
Loop queue: a loop queue that can be added or deleted at both ends
Illustrated structure:
Last = (font + size-1) % array.length); last = (font + size-1) % array.length)
Cyclic interface design
1. Attributes:
private int front;
— Loop queue head pointerprivate int size;
— Number of queue elementsprivate E[] elements;
Use sequential structured array storageprivate static final int DEFAULT_CAPACITY = 10;
— The default initialization value of the array
2. Interface method:
int size();
View the number of current queue elementsboolean isEmpty();
— Checks whether the queue is emptypublic void enQueueRear(E element);
Join the team, from the back of the linepublic E deQueueRear();
Get out, get out of the back of the linepublic void enQueueFront(E element);
Join the team, join the team from the headpublic E enQueueFront();
Get out of the team, get out of the teampublic E front();
Add the fetch header elementpublic E rear();
Add the fetch element to the end of the queuevoid clear();
Clear the queue elementprivate void ensureCapacity(int capacity)
– Ensure that the capacity is sufficient. If not, expand the capacityprivate int index(int index);
Index mapping function that returns the real array subscript
coded
As mentioned above, the structure is the same as the loop queue, so most of the methods are the same, but the functionality has been enhanced and some of the method logic has been adjusted
Method changes:
Public void enQueueFront(E element); Join the team, join the team from the head
/** * join the team from the head *@param element
*/
public void enQueueFront(E element) {
//front points to the position in front of the current node
front = index(-1);
// If front is 0, add to -1 when adding elements to queue header
elements[front] = element;
size++;
}
Copy the code
Public E deQueueRear(); Get out, get out of the back of the line
/** ** from the end of the line *@return* /
public E deQueueRear(a) {
// Find the real index of the tail element
int last = index(size - 1);
E element = elements[last];
elements[last] = null;
size--;
return element;
}
Copy the code
(3) add public E rear(); Add the fetch element to the end of the queue
/** * get the last element *@return* /
public E rear(a) {
return elements[index(size - 1)];
}
Copy the code
(4) change private int index(int index); Index mapping function that returns the real array subscript
/** * index mapping function that returns the real array subscript *@param index
* @return* /
private int index(int index){
index += front;
// If the real index is 0, add an element to the queue header and pass -1, which is less than 0
if (index < 0){
index += elements.length;
}
return index % elements.length;
}
Copy the code
The statement
Personal ability is limited, have incorrect place, also please correct
The article is original, welcome to reprint, just indicate the source
The code for this article has been uploadedgithub
, welcomestar
GitHub
address