e240c1e33c
Co-authored-by: Andrii Siriak <siryaka@gmail.com>
248 lines
5.6 KiB
Java
248 lines
5.6 KiB
Java
package DataStructures.Queues;
|
|
|
|
/**
|
|
* A [deque](https://en.wikipedia.org/wiki/Double-ended_queue) is short for a double ended queue
|
|
* pronounced "deck" and sometimes referred to as a head-tail linked list. A deque is a data
|
|
* structure based on a doubly linked list, but only supports adding and removal of nodes from the
|
|
* beginning and the end of the list.
|
|
*
|
|
* @author [Ian Cowan](https://github.com/iccowan)
|
|
*/
|
|
public class Deques<T> {
|
|
/** Node for the deque */
|
|
class DequeNode<S> {
|
|
/** Value of the node */
|
|
S val;
|
|
|
|
/** Next node in the deque from this node */
|
|
DequeNode<S> next = null;
|
|
|
|
/** Previous node in the deque from this node */
|
|
DequeNode<S> prev = null;
|
|
|
|
/** Constructor */
|
|
DequeNode(S val) {
|
|
this.val = val;
|
|
}
|
|
}
|
|
|
|
/** Head of the deque */
|
|
DequeNode<T> head = null;
|
|
|
|
/** Tail of the deque */
|
|
DequeNode<T> tail = null;
|
|
|
|
/** Size of the deque */
|
|
int size = 0;
|
|
|
|
/**
|
|
* Adds the specified value to the head of the deque
|
|
*
|
|
* @param val Value to add to the deque
|
|
*/
|
|
public void addFirst(T val) {
|
|
// Create a new node with the given value
|
|
DequeNode<T> newNode = new DequeNode<T>(val);
|
|
|
|
// Add the node
|
|
if (head == null) {
|
|
// If the deque is empty, add the node as the head and tail
|
|
head = newNode;
|
|
tail = newNode;
|
|
} else {
|
|
// If the deque is not empty, insert the node as the new head
|
|
newNode.next = head;
|
|
head.prev = newNode;
|
|
head = newNode;
|
|
}
|
|
|
|
size++;
|
|
}
|
|
|
|
/**
|
|
* Adds the specified value to the tail of the deque
|
|
*
|
|
* @param val Value to add to the deque
|
|
*/
|
|
public void addLast(T val) {
|
|
// Create a new node with the given value
|
|
DequeNode<T> newNode = new DequeNode<T>(val);
|
|
|
|
// Add the node
|
|
if (tail == null) {
|
|
// If the deque is empty, add the node as the head and tail
|
|
head = newNode;
|
|
tail = newNode;
|
|
} else {
|
|
// If the deque is not empty, insert the node as the new tail
|
|
newNode.prev = tail;
|
|
tail.next = newNode;
|
|
tail = newNode;
|
|
}
|
|
|
|
size++;
|
|
}
|
|
|
|
/**
|
|
* Removes and returns the first (head) value in the deque
|
|
*
|
|
* @return the value of the head of the deque
|
|
*/
|
|
public T pollFirst() {
|
|
// If the head is null, return null
|
|
if (head == null) return null;
|
|
|
|
// First, let's get the value of the old head
|
|
T oldHeadVal = head.val;
|
|
|
|
// Now, let's remove the head
|
|
if (head == tail) {
|
|
// If there is only one node, remove it
|
|
head = null;
|
|
tail = null;
|
|
} else {
|
|
// If there is more than one node, fix the references
|
|
head.next.prev = null;
|
|
DequeNode<T> oldHead = head;
|
|
head = head.next;
|
|
|
|
// Can be considered unnecessary...
|
|
// Unlinking the old head to make sure there are no random
|
|
// references possibly affecting garbage collection
|
|
oldHead.next = null;
|
|
}
|
|
|
|
size--;
|
|
return oldHeadVal;
|
|
}
|
|
|
|
/**
|
|
* Removes and returns the last (tail) value in the deque
|
|
*
|
|
* @return the value of the tail of the deque
|
|
*/
|
|
public T pollLast() {
|
|
// If the tail is null, return null
|
|
if (tail == null) return null;
|
|
|
|
// Let's get the value of the old tail
|
|
T oldTailVal = tail.val;
|
|
|
|
// Now, remove the tail
|
|
if (head == tail) {
|
|
// If there is only one node, remove it
|
|
head = null;
|
|
tail = null;
|
|
} else {
|
|
// If there is more than one node, fix the references
|
|
tail.prev.next = null;
|
|
DequeNode<T> oldTail = tail;
|
|
tail = tail.prev;
|
|
|
|
// Similarly to above, can be considered unnecessary
|
|
// See `pollFirst()` for explanation
|
|
oldTail.prev = null;
|
|
}
|
|
|
|
size--;
|
|
return oldTailVal;
|
|
}
|
|
|
|
/**
|
|
* Returns the first (head) value of the deque WITHOUT removing
|
|
*
|
|
* @return the value of the head of the deque
|
|
*/
|
|
public T peekFirst() {
|
|
return head.val;
|
|
}
|
|
|
|
/**
|
|
* Returns the last (tail) value of the deque WITHOUT removing
|
|
*
|
|
* @return the value of the tail of the deque
|
|
*/
|
|
public T peekLast() {
|
|
return tail.val;
|
|
}
|
|
|
|
/**
|
|
* Returns the size of the deque
|
|
*
|
|
* @return the size of the deque
|
|
*/
|
|
public int size() {
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* Returns whether or not the deque is empty
|
|
*
|
|
* @return whether or not the deque is empty
|
|
*/
|
|
public boolean isEmpty() {
|
|
return head == null;
|
|
}
|
|
|
|
/**
|
|
* Returns a stringified deque in a pretty form:
|
|
*
|
|
* <p>Head -> 1 <-> 2 <-> 3 <- Tail
|
|
*
|
|
* @return the stringified deque
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
String dequeString = "Head -> ";
|
|
DequeNode<T> currNode = head;
|
|
while (currNode != null) {
|
|
dequeString += currNode.val;
|
|
|
|
if (currNode.next != null) dequeString += " <-> ";
|
|
|
|
currNode = currNode.next;
|
|
}
|
|
|
|
dequeString += " <- Tail";
|
|
|
|
return dequeString;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
Deques<Integer> myDeque = new Deques<Integer>();
|
|
for (int i = 0; i < 42; i++) {
|
|
if (i / 42.0 < 0.5) {
|
|
myDeque.addFirst(i);
|
|
} else {
|
|
myDeque.addLast(i);
|
|
}
|
|
}
|
|
|
|
System.out.println(myDeque);
|
|
System.out.println("Size: " + myDeque.size());
|
|
System.out.println();
|
|
|
|
myDeque.pollFirst();
|
|
myDeque.pollFirst();
|
|
myDeque.pollLast();
|
|
System.out.println(myDeque);
|
|
System.out.println("Size: " + myDeque.size());
|
|
System.out.println();
|
|
|
|
int dequeSize = myDeque.size();
|
|
for (int i = 0; i < dequeSize; i++) {
|
|
int removing = -1;
|
|
if (i / 39.0 < 0.5) {
|
|
removing = myDeque.pollFirst();
|
|
} else {
|
|
removing = myDeque.pollLast();
|
|
}
|
|
|
|
System.out.println("Removing: " + removing);
|
|
}
|
|
|
|
System.out.println(myDeque);
|
|
System.out.println(myDeque.size());
|
|
}
|
|
}
|