Skip to content

Commit a03353d

Browse files
authored
refactor: Deque (#5353)
1 parent e756a7d commit a03353d

File tree

2 files changed

+119
-89
lines changed
  • src
    • main/java/com/thealgorithms/datastructures/queues
    • test/java/com/thealgorithms/datastructures/queues

2 files changed

+119
-89
lines changed

src/main/java/com/thealgorithms/datastructures/queues/Deques.java renamed to src/main/java/com/thealgorithms/datastructures/queues/Deque.java

+29-89
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.thealgorithms.datastructures.queues;
22

3+
import java.util.NoSuchElementException;
4+
35
/**
46
* A [deque](https://en.wikipedia.org/wiki/Double-ended_queue) is short for a
57
* double ended queue pronounced "deck" and sometimes referred to as a head-tail
@@ -9,67 +11,37 @@
911
*
1012
* @author [Ian Cowan](https://github.com/iccowan)
1113
*/
12-
public class Deques<T> {
14+
public class Deque<T> {
1315

1416
/**
1517
* Node for the deque
1618
*/
17-
class DequeNode<S> {
18-
19-
/**
20-
* Value of the node
21-
*/
19+
private static class DequeNode<S> {
2220
S val;
23-
24-
/**
25-
* Next node in the deque from this node
26-
*/
2721
DequeNode<S> next = null;
28-
29-
/**
30-
* Previous node in the deque from this node
31-
*/
3222
DequeNode<S> prev = null;
3323

34-
/**
35-
* Constructor
36-
*/
3724
DequeNode(S val) {
3825
this.val = val;
3926
}
4027
}
4128

42-
/**
43-
* Head of the deque
44-
*/
45-
DequeNode<T> head = null;
46-
47-
/**
48-
* Tail of the deque
49-
*/
50-
DequeNode<T> tail = null;
51-
52-
/**
53-
* Size of the deque
54-
*/
55-
int size = 0;
29+
private DequeNode<T> head = null;
30+
private DequeNode<T> tail = null;
31+
private int size = 0;
5632

5733
/**
5834
* Adds the specified value to the head of the deque
5935
*
6036
* @param val Value to add to the deque
6137
*/
6238
public void addFirst(T val) {
63-
// Create a new node with the given value
64-
DequeNode<T> newNode = new DequeNode<T>(val);
39+
DequeNode<T> newNode = new DequeNode<>(val);
6540

66-
// Add the node
67-
if (head == null) {
68-
// If the deque is empty, add the node as the head and tail
41+
if (isEmpty()) {
6942
head = newNode;
7043
tail = newNode;
7144
} else {
72-
// If the deque is not empty, insert the node as the new head
7345
newNode.next = head;
7446
head.prev = newNode;
7547
head = newNode;
@@ -84,54 +56,37 @@ public void addFirst(T val) {
8456
* @param val Value to add to the deque
8557
*/
8658
public void addLast(T val) {
87-
// Create a new node with the given value
88-
DequeNode<T> newNode = new DequeNode<T>(val);
89-
90-
// Add the node
59+
DequeNode<T> newNode = new DequeNode<>(val);
9160
if (tail == null) {
92-
// If the deque is empty, add the node as the head and tail
9361
head = newNode;
62+
tail = newNode;
9463
} else {
95-
// If the deque is not empty, insert the node as the new tail
9664
newNode.prev = tail;
9765
tail.next = newNode;
66+
tail = newNode;
9867
}
99-
tail = newNode;
100-
10168
size++;
10269
}
10370

10471
/**
10572
* Removes and returns the first (head) value in the deque
10673
*
10774
* @return the value of the head of the deque
75+
* @throws NoSuchElementException if the deque is empty
10876
*/
10977
public T pollFirst() {
110-
// If the head is null, return null
11178
if (head == null) {
112-
return null;
79+
throw new NoSuchElementException("Deque is empty");
11380
}
11481

115-
// First, let's get the value of the old head
11682
T oldHeadVal = head.val;
117-
118-
// Now, let's remove the head
11983
if (head == tail) {
120-
// If there is only one node, remove it
12184
head = null;
12285
tail = null;
12386
} else {
124-
// If there is more than one node, fix the references
125-
head.next.prev = null;
126-
DequeNode<T> oldHead = head;
12787
head = head.next;
128-
129-
// Can be considered unnecessary...
130-
// Unlinking the old head to make sure there are no random
131-
// references possibly affecting garbage collection
132-
oldHead.next = null;
88+
head.prev = null;
13389
}
134-
13590
size--;
13691
return oldHeadVal;
13792
}
@@ -140,52 +95,41 @@ public T pollFirst() {
14095
* Removes and returns the last (tail) value in the deque
14196
*
14297
* @return the value of the tail of the deque
98+
* @throws NoSuchElementException if the deque is empty
14399
*/
144100
public T pollLast() {
145-
// If the tail is null, return null
146101
if (tail == null) {
147-
return null;
102+
throw new NoSuchElementException("Deque is empty");
148103
}
149104

150-
// Let's get the value of the old tail
151105
T oldTailVal = tail.val;
152-
153-
// Now, remove the tail
154106
if (head == tail) {
155-
// If there is only one node, remove it
156107
head = null;
157108
tail = null;
158109
} else {
159-
// If there is more than one node, fix the references
160-
tail.prev.next = null;
161-
DequeNode<T> oldTail = tail;
162110
tail = tail.prev;
163-
164-
// Similarly to above, can be considered unnecessary
165-
// See `pollFirst()` for explanation
166-
oldTail.prev = null;
111+
tail.next = null;
167112
}
168-
169113
size--;
170114
return oldTailVal;
171115
}
172116

173117
/**
174118
* Returns the first (head) value of the deque WITHOUT removing
175119
*
176-
* @return the value of the head of the deque
120+
* @return the value of the head of the deque, or null if empty
177121
*/
178122
public T peekFirst() {
179-
return head.val;
123+
return head != null ? head.val : null;
180124
}
181125

182126
/**
183127
* Returns the last (tail) value of the deque WITHOUT removing
184128
*
185-
* @return the value of the tail of the deque
129+
* @return the value of the tail of the deque, or null if empty
186130
*/
187131
public T peekLast() {
188-
return tail.val;
132+
return tail != null ? tail.val : null;
189133
}
190134

191135
/**
@@ -203,7 +147,7 @@ public int size() {
203147
* @return whether or not the deque is empty
204148
*/
205149
public boolean isEmpty() {
206-
return head == null;
150+
return size == 0;
207151
}
208152

209153
/**
@@ -216,25 +160,21 @@ public boolean isEmpty() {
216160
*/
217161
@Override
218162
public String toString() {
219-
String dequeString = "Head -> ";
163+
StringBuilder dequeString = new StringBuilder("Head -> ");
220164
DequeNode<T> currNode = head;
221165
while (currNode != null) {
222-
dequeString += currNode.val;
223-
166+
dequeString.append(currNode.val);
224167
if (currNode.next != null) {
225-
dequeString += " <-> ";
168+
dequeString.append(" <-> ");
226169
}
227-
228170
currNode = currNode.next;
229171
}
230-
231-
dequeString += " <- Tail";
232-
233-
return dequeString;
172+
dequeString.append(" <- Tail");
173+
return dequeString.toString();
234174
}
235175

236176
public static void main(String[] args) {
237-
Deques<Integer> myDeque = new Deques<Integer>();
177+
Deque<Integer> myDeque = new Deque<>();
238178
for (int i = 0; i < 42; i++) {
239179
if (i / 42.0 < 0.5) {
240180
myDeque.addFirst(i);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.thealgorithms.datastructures.queues;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertNull;
6+
7+
import java.util.NoSuchElementException;
8+
import org.junit.jupiter.api.Test;
9+
10+
class DequeTest {
11+
12+
@Test
13+
void testAddFirst() {
14+
Deque<Integer> deque = new Deque<>();
15+
deque.addFirst(10);
16+
assertEquals(10, deque.peekFirst());
17+
assertEquals(10, deque.peekLast());
18+
assertEquals(1, deque.size());
19+
}
20+
21+
@Test
22+
void testAddLast() {
23+
Deque<Integer> deque = new Deque<>();
24+
deque.addLast(20);
25+
assertEquals(20, deque.peekFirst());
26+
assertEquals(20, deque.peekLast());
27+
assertEquals(1, deque.size());
28+
}
29+
30+
@Test
31+
void testPollFirst() {
32+
Deque<Integer> deque = new Deque<>();
33+
deque.addFirst(10);
34+
deque.addLast(20);
35+
assertEquals(10, deque.pollFirst());
36+
assertEquals(20, deque.peekFirst());
37+
assertEquals(1, deque.size());
38+
}
39+
40+
@Test
41+
void testPollLast() {
42+
Deque<Integer> deque = new Deque<>();
43+
deque.addFirst(10);
44+
deque.addLast(20);
45+
assertEquals(20, deque.pollLast());
46+
assertEquals(10, deque.peekLast());
47+
assertEquals(1, deque.size());
48+
}
49+
50+
@Test
51+
void testIsEmpty() {
52+
Deque<Integer> deque = new Deque<>();
53+
org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty());
54+
deque.addFirst(10);
55+
assertFalse(deque.isEmpty());
56+
}
57+
58+
@Test
59+
void testPeekFirstEmpty() {
60+
Deque<Integer> deque = new Deque<>();
61+
assertNull(deque.peekFirst());
62+
}
63+
64+
@Test
65+
void testPeekLastEmpty() {
66+
Deque<Integer> deque = new Deque<>();
67+
assertNull(deque.peekLast());
68+
}
69+
70+
@Test
71+
void testPollFirstEmpty() {
72+
Deque<Integer> deque = new Deque<>();
73+
org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, deque::pollFirst);
74+
}
75+
76+
@Test
77+
void testPollLastEmpty() {
78+
Deque<Integer> deque = new Deque<>();
79+
org.junit.jupiter.api.Assertions.assertThrows(NoSuchElementException.class, deque::pollLast);
80+
}
81+
82+
@Test
83+
void testToString() {
84+
Deque<Integer> deque = new Deque<>();
85+
deque.addFirst(10);
86+
deque.addLast(20);
87+
deque.addFirst(5);
88+
assertEquals("Head -> 5 <-> 10 <-> 20 <- Tail", deque.toString());
89+
}
90+
}

0 commit comments

Comments
 (0)