Skip to content

Commit e160c6e

Browse files
committed
doubly linked list implementation
1 parent cfe73ee commit e160c6e

File tree

2 files changed

+318
-0
lines changed

2 files changed

+318
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package problems.impl;
2+
3+
public class DoublyLinkedList {
4+
public static class Node {
5+
private Node previous;
6+
private Node next;
7+
private int value;
8+
9+
public Node(int value) {
10+
this.value = value;
11+
}
12+
13+
public Node getPrevious() {
14+
return previous;
15+
}
16+
17+
public Node getNext() {
18+
return next;
19+
}
20+
21+
public int getValue() {
22+
return value;
23+
}
24+
}
25+
26+
private Node head;
27+
private Node tail;
28+
private int length = 0;
29+
30+
public DoublyLinkedList() {
31+
}
32+
33+
public Node getHead() {
34+
return head;
35+
}
36+
37+
public Node getTail() {
38+
return tail;
39+
}
40+
41+
public int getLength() {
42+
return length;
43+
}
44+
45+
public boolean isEmpty() {
46+
return length == 0;
47+
}
48+
49+
public void insertAtHead(int value) {
50+
insertNode(null, new Node(value), head);
51+
}
52+
53+
public void insertAtTail(int value) {
54+
insertNode(tail, new Node(value), null);
55+
}
56+
57+
public void insertAt(int value, int index) {
58+
if (index > length || index < 0) {
59+
throw new IndexOutOfBoundsException("index of " + index + " is out of bounds");
60+
}
61+
62+
Node node = new Node(value);
63+
Node previousNode = null;
64+
Node currentNodeAtIndex = head;
65+
for (int i = 0; i < index; i++) {
66+
previousNode = currentNodeAtIndex;
67+
currentNodeAtIndex = currentNodeAtIndex.next;
68+
}
69+
insertNode(previousNode, node, currentNodeAtIndex);
70+
}
71+
72+
public void removeFirstOccurrence(int value) {
73+
Node currentNode = head;
74+
while (currentNode != null) {
75+
if (currentNode.value == value) {
76+
removeNode(currentNode);
77+
return;
78+
}
79+
currentNode = currentNode.next;
80+
}
81+
}
82+
83+
public void removeAt(int index) {
84+
if (index >= length || index < 0) {
85+
throw new IndexOutOfBoundsException("index of " + index + " is out of bounds");
86+
}
87+
88+
Node currentNodeAtIndex = head;
89+
for (int i = 0; i < index; i++) {
90+
currentNodeAtIndex = currentNodeAtIndex.next;
91+
}
92+
93+
removeNode(currentNodeAtIndex);
94+
}
95+
96+
private void removeNode(Node node) {
97+
if (node.previous == null) {
98+
head = node.next;
99+
}
100+
101+
if (node.next == null) {
102+
tail = node.previous;
103+
}
104+
105+
if (node.previous != null && node.next != null) {
106+
node.previous.next = node.next;
107+
node.next.previous = node.previous;
108+
}
109+
110+
length--;
111+
}
112+
113+
private void insertNode(Node nodeBefore, Node node, Node nodeAfter) {
114+
if (nodeBefore == null) {
115+
head = node;
116+
}
117+
118+
if (nodeAfter == null) {
119+
tail = node;
120+
}
121+
122+
node.next = nodeAfter;
123+
node.previous = nodeBefore;
124+
125+
length++;
126+
}
127+
}
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
package problems.impl;
2+
3+
import org.junit.Test;
4+
5+
import static org.junit.Assert.*;
6+
import static problems.impl.DoublyLinkedList.*;
7+
8+
public class DoublyLinkedListTest {
9+
10+
@Test
11+
public void insertAtHead() {
12+
DoublyLinkedList list = new DoublyLinkedList();
13+
list.insertAtHead(1);
14+
assertEquals(1, list.getLength());
15+
Node head = list.getHead();
16+
assertEquals(1, head.getValue());
17+
assertNull(head.getNext());
18+
assertNull(head.getPrevious());
19+
assertEquals(list.getHead(), list.getTail());
20+
}
21+
22+
@Test
23+
public void insertAtHeadTwice() {
24+
DoublyLinkedList list = new DoublyLinkedList();
25+
list.insertAtHead(2);
26+
list.insertAtHead(1);
27+
assertEquals(2, list.getLength());
28+
assertEquals(1, list.getHead().getValue());
29+
assertEquals(2, list.getTail().getValue());
30+
}
31+
32+
@Test
33+
public void insertAtTail() {
34+
DoublyLinkedList list = new DoublyLinkedList();
35+
list.insertAtTail(1);
36+
assertEquals(1, list.getLength());
37+
Node head = list.getHead();
38+
assertEquals(1, head.getValue());
39+
assertNull(head.getNext());
40+
assertNull(head.getPrevious());
41+
assertEquals(list.getHead(), list.getTail());
42+
}
43+
44+
@Test
45+
public void insertAtTailTwice() {
46+
DoublyLinkedList list = new DoublyLinkedList();
47+
list.insertAtTail(1);
48+
list.insertAtTail(2);
49+
assertEquals(2, list.getLength());
50+
assertEquals(1, list.getHead().getValue());
51+
assertEquals(2, list.getTail().getValue());
52+
}
53+
54+
@Test
55+
public void insertAtZero() {
56+
DoublyLinkedList list = new DoublyLinkedList();
57+
list.insertAt(1, 0);
58+
assertEquals(1, list.getLength());
59+
Node head = list.getHead();
60+
assertEquals(1, head.getValue());
61+
assertNull(head.getNext());
62+
assertNull(head.getPrevious());
63+
assertEquals(list.getHead(), list.getTail());
64+
}
65+
66+
@Test
67+
public void insertAtIndexAtEndOfList() {
68+
DoublyLinkedList list = new DoublyLinkedList();
69+
list.insertAt(1, 0);
70+
assertEquals(1, list.getLength());
71+
Node head = list.getHead();
72+
assertEquals(1, head.getValue());
73+
assertNull(head.getNext());
74+
assertNull(head.getPrevious());
75+
assertEquals(list.getHead(), list.getTail());
76+
list.insertAt(2, 1);
77+
assertEquals(2, list.getLength());
78+
assertEquals(1, list.getHead().getValue());
79+
assertEquals(2, list.getTail().getValue());
80+
}
81+
82+
@Test
83+
public void insertAtOneThrows() {
84+
DoublyLinkedList list = new DoublyLinkedList();
85+
try {
86+
list.insertAt(1, 1);
87+
} catch (Exception e) {
88+
// expected
89+
return;
90+
}
91+
fail();
92+
}
93+
94+
@Test
95+
public void insertAtNegativeIndexThrows() {
96+
DoublyLinkedList list = new DoublyLinkedList();
97+
try {
98+
list.insertAt(1, -1);
99+
} catch (Exception e) {
100+
// expected
101+
return;
102+
}
103+
fail();
104+
}
105+
106+
@Test
107+
public void isEmpty() {
108+
DoublyLinkedList list = new DoublyLinkedList();
109+
assertTrue(list.isEmpty());
110+
}
111+
112+
@Test
113+
public void isNotEmpty() {
114+
DoublyLinkedList list = new DoublyLinkedList();
115+
list.insertAtHead(1);
116+
assertFalse(list.isEmpty());
117+
}
118+
119+
@Test
120+
public void removeFirstOccurrenceEmptyList() {
121+
DoublyLinkedList list = new DoublyLinkedList();
122+
assertTrue(list.isEmpty());
123+
list.removeFirstOccurrence(1);
124+
assertTrue(list.isEmpty());
125+
}
126+
127+
@Test
128+
public void removeFirstOccurrenceRemovesElement() {
129+
DoublyLinkedList list = new DoublyLinkedList();
130+
list.insertAtHead(1);
131+
assertFalse(list.isEmpty());
132+
list.removeFirstOccurrence(1);
133+
assertTrue(list.isEmpty());
134+
assertNull(list.getHead());
135+
assertEquals(list.getHead(), list.getTail());
136+
}
137+
138+
@Test
139+
public void removesOnlyFirstOccurrenceLeavesOthers() {
140+
DoublyLinkedList list = new DoublyLinkedList();
141+
list.insertAtHead(1);
142+
list.insertAtHead(2);
143+
list.insertAtHead(1);
144+
assertFalse(list.isEmpty());
145+
list.removeFirstOccurrence(1);
146+
assertFalse(list.isEmpty());
147+
assertEquals(2, list.getLength());
148+
assertEquals(2, list.getHead().getValue());
149+
assertEquals(1, list.getTail().getValue());
150+
}
151+
152+
@Test
153+
public void removeAtForEmptyListThrows() {
154+
DoublyLinkedList list = new DoublyLinkedList();
155+
try {
156+
list.removeAt(0);
157+
} catch (Exception e) {
158+
// expected
159+
return;
160+
}
161+
162+
fail();
163+
}
164+
165+
@Test
166+
public void removeAtNegativeIndexThrows() {
167+
DoublyLinkedList list = new DoublyLinkedList();
168+
list.insertAtHead(1);
169+
try {
170+
list.removeAt(-1);
171+
} catch (Exception e) {
172+
// expected
173+
return;
174+
}
175+
176+
fail();
177+
}
178+
179+
@Test
180+
public void removeAtZeroForSingleElementList() {
181+
DoublyLinkedList list = new DoublyLinkedList();
182+
list.insertAtHead(1);
183+
assertEquals(1, list.getLength());
184+
assertEquals(1, list.getHead().getValue());
185+
assertEquals(list.getHead(), list.getTail());
186+
list.removeAt(0);
187+
assertEquals(0, list.getLength());
188+
assertNull(list.getHead());
189+
assertEquals(list.getHead(), list.getTail());
190+
}
191+
}

0 commit comments

Comments
 (0)