This is the 12th day of my participation in the First Challenge 2022
The concept of a Queue
A queue is a special linear table that allows operations only at the head and tail of the queue. EnQueue adds an element to the end of the queue. Removing an element from the head of a queue is a deQueue. The queue is First In First Out.
Queue method design
int size(a); // Get the number of elements in the queue
boolean isEmpty(a); // Check whether the queue is empty
void enQueue(T element); // add elements to the end of the column
T deQueue(a); // Remove the element in the header
T front(a); // Get the header element of the queue
void clear(a); // Clear the queue
Copy the code
Queue head and tail operations are frequent and can be implemented based on bidirectional linked lists
Second, the implementation of the queue
Create Module 05-queue in data-structures project, put bidirectional LinkedList LinkedList, abstract LinkedList AbstractList, interface List in com.citi. List package for queue reference. Copy the utility classes from Utils into the com.citi package. Create a new class queue.Queue and make LinkedList private
public class Queue<T> {
// The private attribute LinkedList
private List<T> list = new LinkedList<>();
public int size(a){
return 0;
}
public boolean isEmpty(a){
return false;
}
public void enQueue(T element){}public T deQueue(a){
return null;
}
public T front(a){
return null;
}
public void clear(a){}}Copy the code
Size () and isEmpty() methods
public int size(a){
return list.size();
}
public boolean isEmpty(a){
return list.isEmpty();
}
Copy the code
EnQueue () joins the queue, adding elements to the end of the queue (adding elements to the end of the list)
public void enQueue(T element){
list.add(element);
}
Copy the code
DeQueue () removes the element at the head of the queue (removes the linked header element, index 0)
public T deQueue(a){
return list.remove(0);
}
Copy the code
Front (), gets the queue header element
public T front(){
return list.get(0);
}
Copy the code
clear()
public void clear(a){
list.clear();
}
Copy the code
Create a new test class QueueTest
public class QueueTest {
Queue<Integer> queue = null;
@Before
public void init(a){
queue = new Queue<>();
queue.enQueue(10);
queue.enQueue(20);
queue.enQueue(30);
System.out.println("Init Queue:" + queue);
}
@Test
public void enQueue(a) {
queue.enQueue(50);
System.out.println("The enQueue Queue," + queue);
}
@Test
public void deQueue(a) {
queue.deQueue();
System.out.println("To deQueue Queue," + queue);
}
@Test
public void front(a) {
System.out.println("Front Queue: "+ queue.front()); }}Copy the code
Let’s rewrite the toString method before we test it
@Override
public String toString(a) {
return "Queue{" +
"list=" + list +
'} ';
}
Copy the code
Perform the test
Use Stack to implement Queue
public class QueueByStack {
private Stack<Integer> inStack = new Stack<>();
private Stack<Integer> outStack = new Stack<>();
public void push(int x){
inStack.push(x);
}
public int pop(a){
checkOutStack();
return outStack.pop();
}
public int peek(a){
checkOutStack();
return outStack.peek();
}
public boolean empty(a){
return inStack.isEmpty() && outStack.isEmpty();
}
public void checkOutStack(a){
if (outStack.isEmpty()){
while(! inStack.isEmpty()){ outStack.push(inStack.pop()); }}}}Copy the code
Two – end queue
A double-ended queue is also a queue that can be added and removed at both ends.
Design of two – end queue method
int size(a); // Get the number of elements in the queue
boolean isEmpty(a); // Check whether the queue is empty
void enQueueRear(T element); // add elements to the end of the column
T deQueueFront(a); // Remove the element in the header
void enQueueFront(T element); // Enter the column from the head
T deQueueRear(a); // This tail deletes elements
T front(a); // Get the header element of the queue
T rear(a); // Get the tail element
void clear(a); // Clear the queue
Copy the code
Add a queue Deque based on LinkedList
public class Deque<T> {
private List<T> list = new LinkedList<>();
public int size(a){
return list.size();
}
public boolean isEmpty(a){
return list.isEmpty();
}
public void clear(a){ list.clear(); }}Copy the code
A double-ended queue adds and removes elements from the beginning to the end
public void enQueueRear(T element){
list.add(element);
}
public T deQueueFront(a){
return list.remove(0);
}
public void enQueueFront(T element){
list.add(0, element);
}
public T deQueueRear(a){
return list.remove(list.size() - 1);
}
Copy the code
Gets the elements at the head and tail of a double-ended queue
public T front(a){
return list.get(0);
}
public T rear(a){
return list.get(list.size() - 1);
}
Copy the code
The test class
public class DequeTest {
Deque<Integer> deque = null;
@Before
public void init(a){
deque = new Deque<>();
deque.enQueueRear(10);
deque.enQueueRear(20);
deque.enQueueRear(30);
System.out.println("Init Queue:" + deque);
}
@Test
public void enQueueRear(a) {
deque.enQueueRear(40);
System.out.println("After enQueueRear: " + deque);
}
@Test
public void deQueueFront(a) {
deque.enQueueFront(0);
System.out.println("After deQueueFront: " + deque);
}
@Test
public void enQueueFront(a) {
deque.enQueueFront(40);
System.out.println("After enQueueFront: " + deque);
}
@Test
public void deQueueRear(a) {
deque.deQueueRear();
System.out.println("After deQueueRear: " + deque);
}
@Test
public void front(a) {
System.out.println("Front:" + deque.front());
}
@Test
public void rear(a) {
System.out.println("Rear:"+ deque.rear()); }}Copy the code
Add toString to the Deque class
@Override
public String toString(a) {
return "Deque{" +
"list=" + list +
'} ';
}
Copy the code
Execute all test methods in the test class
Fourth, circular queue
The bottom layer of the loop queue is implemented using an array, which has a front attribute, specifying an index in the array as the head of the queue. Front refers to the index in the array, which is of type int. Front does not necessarily mean the position of index 0
Delete element demo
When the queue head deletes an element, it moves front back one place. When the queue head deletes an element again, it moves front back one place. Front is always smaller than the size of the array
Add element demo
When adding an element, we add the element to the end of the array. The front position is always the same. When there is no space on the right side, we loop through the left side of the array to add an element
Adding to an array when there is no space on the left of the array requires dynamic expansion. A loop in a loop queue is a loop when adding elements.
Circular queues have the same methods as normal queues
Circular queue implementation
public class CircleQueue<T> {
private int size;
private T[] elements;
public static final int DEFAULT_CAPACITY = 10;
// Defines the length of the array
public CircleQueue(a){
elements = (T[]) new Object[DEFAULT_CAPACITY];
}
public int size(a){
return size;
}
public boolean isEmpty(a){
return size == 0; }}Copy the code
Gets the queue header element
public T front(a){
return elements[front];
}
Copy the code
Append element whose index is smaller than the array size
public void enQueue(T element){
elements[(front + size) % elements.length] = element;
size++;
}
Copy the code
Removes the queue header element. Front is smaller than the array size
public T deQueue(a){
// Get the correct element first
T frontEle = elements[front];
// Empty the header element
elements[front] = null;
// The head of the queue should move back once
// front++;
front = (front + 1) % elements.length;
/ / the length - 1
size--;
// return the header element
return frontEle;
}
Copy the code
Clear the elements in the queue, iterate over all the elements, set to NULL
public void clear(a){
for (int i = 0; i < elements.length; i++) {
elements[i] = null;
}
size = 0;
front = 0;
}
Copy the code
Adding test classes
public class CircleQueueTest {
CircleQueue<Integer> queue = null;
@Before
public void init(a){
queue = new CircleQueue<>();
queue.enQueue(11);
queue.enQueue(22);
queue.enQueue(33);
System.out.println("Init CircleQueue: " + queue);
}
@Test
public void front(a) {
System.out.println("CircleQueue Front: " + queue.front());
}
@Test
public void enQueue(a) {
queue.enQueue(55);
System.out.println("After enQueue: " + queue);
}
@Test
public void deQueue(a) {
queue.deQueue();
System.out.println("After deQueue: "+ queue); }}Copy the code
Add toString method
@Override
public String toString(a) {
return "CircleQueue{" +
"front=" + front +
", size=" + size +
", elements=" + Arrays.toString(elements) +
'} ';
}
Copy the code
Execute all test methods
Special case test
@Test
public void deQueueAndEnQueue(a) {
for (int i = 0; i < 3; i++) {
queue.deQueue();
}
System.out.println("After deQueue: " + queue);
for (int i = 0; i < 4; i++) {
queue.enQueue(i + 100);
}
System.out.println("After enQueue: " + queue);
for (int i = 0; i < 8; i++) {
queue.deQueue();
}
System.out.println(queue);
}
Copy the code
Adding capacity Expansion methods
private void expansionCapacity(int newCapacity){
int oldCapacity = elements.length;
if (oldCapacity >= size + 1) return;
// Create an array of new capacities
// newCapacity = oldCapacity + (oldCapacity >> 1);
T[] newElements = (T[]) new Object[newCapacity];
// Copy the element
for (int i = 0; i < size; i++) {
newElements[i] = elements[(i + front) % elements.length];
}
// Points to a new memory space
elements = newElements;
front = 0;
System.out.println("Capacity expansion succeeded." + oldCapacity + "Extend to" + newCapacity);
}
Copy the code
Modify the enQueue method code
public void enQueue(T element){
expansionCapacity(elements.length + (elements.length >> 1));
elements[(front + size) % elements.length] = element;
size++;
}
Copy the code
Expansion test code
@Test
public void testExpansion(a) {
queue.deQueue();
System.out.println(queue);
for (int i = 0; i < 3; i++) {
queue.enQueue(i);
}
System.out.println(queue);
for (int i = 0; i < 3; i++) {
queue.deQueue();
}
System.out.println("After deQueue: " + queue);
for (int i = 0; i < 4; i++) {
queue.enQueue(i + 100);
}
System.out.println("After enQueue: " + queue);
for (int i = 0; i < 8; i++) {
queue.deQueue();
}
System.out.println(queue);
}
Copy the code
Perform the test
5. Loop double – ended queue
A circular queue that can be added and deleted at both ends
Create a new CircleDeque
public class CircleDeque<T> {
private int front;
private int size;
private T[] elements;
public static final int DEFAULT_CAPACITY = 10;
// Defines the length of the array
public CircleDeque(a){
elements = (T[]) new Object[DEFAULT_CAPACITY];
}
public int size(a){
return size;
}
public boolean isEmpty(a){
return size == 0;
}
public void clear(a){
for (int i = 0; i < elements.length; i++) {
elements[index(i)] = null;
}
size = 0;
front = 0;
}
public int index(int index){
return (front + index) % elements.length;
}
private void expansionCapacity(int newCapacity){
int oldCapacity = elements.length;
if (oldCapacity >= size + 1) return;
// Create an array of new capacities
// newCapacity = oldCapacity + (oldCapacity >> 1);
T[] newElements = (T[]) new Object[newCapacity];
// Copy the element
for (int i = 0; i < size; i++) {
newElements[i] = elements[(i + front) % elements.length];
}
// Points to a new memory space
elements = newElements;
front = 0;
System.out.println("Capacity expansion succeeded." + oldCapacity + "Extend to" + newCapacity);
}
@Override
public String toString(a) {
return "CircleQueue{" +
"front=" + front +
", size=" + size +
", elements=" + Arrays.toString(elements) +
'} '; }}Copy the code
Gets the header and tail elements
public T front(a){
return elements[front];
}
public T rear(a){
return elements[index(front + size - 1)];
}
Copy the code
Joining the queue from the tail and removing the queue from the head are consistent with the method of two-ended queuing
// Enter the queue from the rear
public void enQueueRear(T element){
expansionCapacity(elements.length + (elements.length >> 1));
elements[(front + size) % elements.length] = element;
size++;
}
// Exit from the head
public T deQueueFront(a){
// Get the correct element first
T frontEle = elements[front];
// Empty the header element
elements[front] = null;
// The head of the queue should move back once
// front++;
front = (front + 1) % elements.length;
/ / the length - 1
size--;
// return the header element
return frontEle;
}
Copy the code
If front is 0, then insert position -1, there is no index -1 in the array, use -1 + array length to create the index in the real array, index method needs to add judgment
public int index(int index){
index += front;
if (index < 0) {return index + elements.length;
}
return (front + index) % elements.length;
}
Copy the code
From the tail out of the team and from the head into the team method
// Exit from the rear
public T deQueueRear(a){
// Get the real index
int rearIndex = index(size - 1);
T rear = elements[rearIndex];
elements[rearIndex] = null;
size--;
return rear;
}
// Enter the team from the head
public void enQueueFront(T element){
expansionCapacity(elements.length + (elements.length >> 1));
front = index(front - 1);
elements[front] = element;
size ++;
}
Copy the code
New Test class
public class CircleDequeTest {
CircleDeque<Integer> deque = null;
@Before
public void init(a){
deque = new CircleDeque<>();
for (int i = 0; i < 8; i++) {
deque.enQueueRear(i + 10);
}
System.out.println("After Init" + deque);
}
@Test
public void front(a) {
System.out.println("CircleDeque Front: " + deque.front());
}
@Test
public void rear(a) {
System.out.println("CircleDeque Rear: " + deque.rear());
}
@Test
public void enQueueRear(a) {
deque.enQueueRear(18);
System.out.println("After enQueueRear:" + deque);
}
@Test
public void deQueueFront(a) {
deque.deQueueFront();
System.out.println("After deQueueFront: " + deque);
}
@Test
public void deQueueRear(a) {
deque.deQueueRear();
System.out.println("After deQueueRear: " + deque);
}
@Test
public void enQueueFront(a) {
deque.enQueueFront(9);
System.out.println("After enQueueFront: "+ deque); }}Copy the code
Perform the test