refactor: Deque
(#5353)
This commit is contained in:
parent
e756a7d2d5
commit
a03353d3d3
@ -1,5 +1,7 @@
|
|||||||
package com.thealgorithms.datastructures.queues;
|
package com.thealgorithms.datastructures.queues;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [deque](https://en.wikipedia.org/wiki/Double-ended_queue) is short for a
|
* 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
|
* double ended queue pronounced "deck" and sometimes referred to as a head-tail
|
||||||
@ -9,50 +11,24 @@ package com.thealgorithms.datastructures.queues;
|
|||||||
*
|
*
|
||||||
* @author [Ian Cowan](https://github.com/iccowan)
|
* @author [Ian Cowan](https://github.com/iccowan)
|
||||||
*/
|
*/
|
||||||
public class Deques<T> {
|
public class Deque<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node for the deque
|
* Node for the deque
|
||||||
*/
|
*/
|
||||||
class DequeNode<S> {
|
private static class DequeNode<S> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Value of the node
|
|
||||||
*/
|
|
||||||
S val;
|
S val;
|
||||||
|
|
||||||
/**
|
|
||||||
* Next node in the deque from this node
|
|
||||||
*/
|
|
||||||
DequeNode<S> next = null;
|
DequeNode<S> next = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Previous node in the deque from this node
|
|
||||||
*/
|
|
||||||
DequeNode<S> prev = null;
|
DequeNode<S> prev = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
DequeNode(S val) {
|
DequeNode(S val) {
|
||||||
this.val = val;
|
this.val = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private DequeNode<T> head = null;
|
||||||
* Head of the deque
|
private DequeNode<T> tail = null;
|
||||||
*/
|
private int size = 0;
|
||||||
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
|
* Adds the specified value to the head of the deque
|
||||||
@ -60,16 +36,12 @@ public class Deques<T> {
|
|||||||
* @param val Value to add to the deque
|
* @param val Value to add to the deque
|
||||||
*/
|
*/
|
||||||
public void addFirst(T val) {
|
public void addFirst(T val) {
|
||||||
// Create a new node with the given value
|
DequeNode<T> newNode = new DequeNode<>(val);
|
||||||
DequeNode<T> newNode = new DequeNode<T>(val);
|
|
||||||
|
|
||||||
// Add the node
|
if (isEmpty()) {
|
||||||
if (head == null) {
|
|
||||||
// If the deque is empty, add the node as the head and tail
|
|
||||||
head = newNode;
|
head = newNode;
|
||||||
tail = newNode;
|
tail = newNode;
|
||||||
} else {
|
} else {
|
||||||
// If the deque is not empty, insert the node as the new head
|
|
||||||
newNode.next = head;
|
newNode.next = head;
|
||||||
head.prev = newNode;
|
head.prev = newNode;
|
||||||
head = newNode;
|
head = newNode;
|
||||||
@ -84,20 +56,15 @@ public class Deques<T> {
|
|||||||
* @param val Value to add to the deque
|
* @param val Value to add to the deque
|
||||||
*/
|
*/
|
||||||
public void addLast(T val) {
|
public void addLast(T val) {
|
||||||
// Create a new node with the given value
|
DequeNode<T> newNode = new DequeNode<>(val);
|
||||||
DequeNode<T> newNode = new DequeNode<T>(val);
|
|
||||||
|
|
||||||
// Add the node
|
|
||||||
if (tail == null) {
|
if (tail == null) {
|
||||||
// If the deque is empty, add the node as the head and tail
|
|
||||||
head = newNode;
|
head = newNode;
|
||||||
|
tail = newNode;
|
||||||
} else {
|
} else {
|
||||||
// If the deque is not empty, insert the node as the new tail
|
|
||||||
newNode.prev = tail;
|
newNode.prev = tail;
|
||||||
tail.next = newNode;
|
tail.next = newNode;
|
||||||
}
|
|
||||||
tail = newNode;
|
tail = newNode;
|
||||||
|
}
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,33 +72,21 @@ public class Deques<T> {
|
|||||||
* Removes and returns the first (head) value in the deque
|
* Removes and returns the first (head) value in the deque
|
||||||
*
|
*
|
||||||
* @return the value of the head of the deque
|
* @return the value of the head of the deque
|
||||||
|
* @throws NoSuchElementException if the deque is empty
|
||||||
*/
|
*/
|
||||||
public T pollFirst() {
|
public T pollFirst() {
|
||||||
// If the head is null, return null
|
|
||||||
if (head == null) {
|
if (head == null) {
|
||||||
return null;
|
throw new NoSuchElementException("Deque is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, let's get the value of the old head
|
|
||||||
T oldHeadVal = head.val;
|
T oldHeadVal = head.val;
|
||||||
|
|
||||||
// Now, let's remove the head
|
|
||||||
if (head == tail) {
|
if (head == tail) {
|
||||||
// If there is only one node, remove it
|
|
||||||
head = null;
|
head = null;
|
||||||
tail = null;
|
tail = null;
|
||||||
} else {
|
} else {
|
||||||
// If there is more than one node, fix the references
|
|
||||||
head.next.prev = null;
|
|
||||||
DequeNode<T> oldHead = head;
|
|
||||||
head = head.next;
|
head = head.next;
|
||||||
|
head.prev = null;
|
||||||
// Can be considered unnecessary...
|
|
||||||
// Unlinking the old head to make sure there are no random
|
|
||||||
// references possibly affecting garbage collection
|
|
||||||
oldHead.next = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size--;
|
size--;
|
||||||
return oldHeadVal;
|
return oldHeadVal;
|
||||||
}
|
}
|
||||||
@ -140,32 +95,21 @@ public class Deques<T> {
|
|||||||
* Removes and returns the last (tail) value in the deque
|
* Removes and returns the last (tail) value in the deque
|
||||||
*
|
*
|
||||||
* @return the value of the tail of the deque
|
* @return the value of the tail of the deque
|
||||||
|
* @throws NoSuchElementException if the deque is empty
|
||||||
*/
|
*/
|
||||||
public T pollLast() {
|
public T pollLast() {
|
||||||
// If the tail is null, return null
|
|
||||||
if (tail == null) {
|
if (tail == null) {
|
||||||
return null;
|
throw new NoSuchElementException("Deque is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's get the value of the old tail
|
|
||||||
T oldTailVal = tail.val;
|
T oldTailVal = tail.val;
|
||||||
|
|
||||||
// Now, remove the tail
|
|
||||||
if (head == tail) {
|
if (head == tail) {
|
||||||
// If there is only one node, remove it
|
|
||||||
head = null;
|
head = null;
|
||||||
tail = null;
|
tail = null;
|
||||||
} else {
|
} else {
|
||||||
// If there is more than one node, fix the references
|
|
||||||
tail.prev.next = null;
|
|
||||||
DequeNode<T> oldTail = tail;
|
|
||||||
tail = tail.prev;
|
tail = tail.prev;
|
||||||
|
tail.next = null;
|
||||||
// Similarly to above, can be considered unnecessary
|
|
||||||
// See `pollFirst()` for explanation
|
|
||||||
oldTail.prev = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size--;
|
size--;
|
||||||
return oldTailVal;
|
return oldTailVal;
|
||||||
}
|
}
|
||||||
@ -173,19 +117,19 @@ public class Deques<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns the first (head) value of the deque WITHOUT removing
|
* Returns the first (head) value of the deque WITHOUT removing
|
||||||
*
|
*
|
||||||
* @return the value of the head of the deque
|
* @return the value of the head of the deque, or null if empty
|
||||||
*/
|
*/
|
||||||
public T peekFirst() {
|
public T peekFirst() {
|
||||||
return head.val;
|
return head != null ? head.val : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the last (tail) value of the deque WITHOUT removing
|
* Returns the last (tail) value of the deque WITHOUT removing
|
||||||
*
|
*
|
||||||
* @return the value of the tail of the deque
|
* @return the value of the tail of the deque, or null if empty
|
||||||
*/
|
*/
|
||||||
public T peekLast() {
|
public T peekLast() {
|
||||||
return tail.val;
|
return tail != null ? tail.val : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,7 +147,7 @@ public class Deques<T> {
|
|||||||
* @return whether or not the deque is empty
|
* @return whether or not the deque is empty
|
||||||
*/
|
*/
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return head == null;
|
return size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,25 +160,21 @@ public class Deques<T> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String dequeString = "Head -> ";
|
StringBuilder dequeString = new StringBuilder("Head -> ");
|
||||||
DequeNode<T> currNode = head;
|
DequeNode<T> currNode = head;
|
||||||
while (currNode != null) {
|
while (currNode != null) {
|
||||||
dequeString += currNode.val;
|
dequeString.append(currNode.val);
|
||||||
|
|
||||||
if (currNode.next != null) {
|
if (currNode.next != null) {
|
||||||
dequeString += " <-> ";
|
dequeString.append(" <-> ");
|
||||||
}
|
}
|
||||||
|
|
||||||
currNode = currNode.next;
|
currNode = currNode.next;
|
||||||
}
|
}
|
||||||
|
dequeString.append(" <- Tail");
|
||||||
dequeString += " <- Tail";
|
return dequeString.toString();
|
||||||
|
|
||||||
return dequeString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Deques<Integer> myDeque = new Deques<Integer>();
|
Deque<Integer> myDeque = new Deque<>();
|
||||||
for (int i = 0; i < 42; i++) {
|
for (int i = 0; i < 42; i++) {
|
||||||
if (i / 42.0 < 0.5) {
|
if (i / 42.0 < 0.5) {
|
||||||
myDeque.addFirst(i);
|
myDeque.addFirst(i);
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.thealgorithms.datastructures.queues;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class DequeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAddFirst() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
deque.addFirst(10);
|
||||||
|
assertEquals(10, deque.peekFirst());
|
||||||
|
assertEquals(10, deque.peekLast());
|
||||||
|
assertEquals(1, deque.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAddLast() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
deque.addLast(20);
|
||||||
|
assertEquals(20, deque.peekFirst());
|
||||||
|
assertEquals(20, deque.peekLast());
|
||||||
|
assertEquals(1, deque.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPollFirst() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
deque.addFirst(10);
|
||||||
|
deque.addLast(20);
|
||||||
|
assertEquals(10, deque.pollFirst());
|
||||||
|
assertEquals(20, deque.peekFirst());
|
||||||
|
assertEquals(1, deque.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPollLast() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
deque.addFirst(10);
|
||||||
|
deque.addLast(20);
|
||||||
|
assertEquals(20, deque.pollLast());
|
||||||
|
assertEquals(10, deque.peekLast());
|
||||||
|
assertEquals(1, deque.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testIsEmpty() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty());
|
||||||
|
deque.addFirst(10);
|
||||||
|
assertFalse(deque.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPeekFirstEmpty() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
assertNull(deque.peekFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPeekLastEmpty() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
assertNull(deque.peekLast());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPollFirstEmpty() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, deque::pollFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPollLastEmpty() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, deque::pollLast);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToString() {
|
||||||
|
Deque<Integer> deque = new Deque<>();
|
||||||
|
deque.addFirst(10);
|
||||||
|
deque.addLast(20);
|
||||||
|
deque.addFirst(5);
|
||||||
|
assertEquals("Head -> 5 <-> 10 <-> 20 <- Tail", deque.toString());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user