Skip to content

Commit 3dc7a18

Browse files
authored
Merge pull request #92 from jaebradley/double-linked-list
Double linked list
2 parents cfe73ee + 55866a3 commit 3dc7a18

File tree

3 files changed

+558
-0
lines changed

3 files changed

+558
-0
lines changed

codereview/DoublyLinkedList.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
## Purpose
2+
3+
I've never implemented a `DoublyLinkedList` and thought it would be a good data structure exercise. I tried using outside
4+
resources as little as possible. I also tried to keep things as simple as possible
5+
6+
## Discussion
7+
8+
The `DoublyLinkedList` is made up of a `Node` `head`, a `Node` `tail`, and an `int` `length`. I did not genericize the
9+
API to keep things simple - the API only deals with `int` values.
10+
11+
The API is
12+
13+
* `getHead` - gets the `Node` at the `head` of the linked list in `O(1)`
14+
* `getTail` - gets the `Node` at the `tail` of the linked list in `O(1)`
15+
* `getLength` - gets the `length` of the linked list in `O(1)`
16+
* `isEmpty` - convenience method; returns `true` if `length` is `0` and `false` otherwise in `O(1)`
17+
* `insertAtHead` - adds the input value at the `head` of the linked list in `O(1)`
18+
* `insertAtTail` - adds the input value at the `tail` of the linked list in `O(1)`
19+
* `insertAt` - adds the input value at some index in the linked list in `O(n)`
20+
* `removeFirstOccurrence` - removes the first occurrence of the input value (if it exists in list) in `O(n)`
21+
* `removeAt` - removes the node at the specified index in the linked list in `O(n)`
22+
* `removeHead` - removes the node at the `head` of the linked list in `O(1)`
23+
* `removeTail` - removes the node at the `tail` of the linked list in `O(1)`
24+
25+
Things I can improve:
26+
27+
* When inserting at / removing at a particular index, I could speed up execution time by picking to start
28+
at the beginning or end of the list based on which the index is closest to
29+
* I tried adding a bunch of test cases, but I could have easily missed a case
30+
* Is my API sane / reasonable / did I miss implementing any obvious methods?
31+
32+
## Implementation
33+
34+
<!-- language:lang-java --!>
35+
36+
public class DoublyLinkedList {
37+
public static class Node {
38+
private Node previous;
39+
private Node next;
40+
private int value;
41+
42+
public Node(int value) {
43+
this.value = value;
44+
}
45+
46+
public Node getPrevious() {
47+
return previous;
48+
}
49+
50+
public Node getNext() {
51+
return next;
52+
}
53+
54+
public int getValue() {
55+
return value;
56+
}
57+
}
58+
59+
private Node head;
60+
private Node tail;
61+
private int length;
62+
63+
public DoublyLinkedList() {
64+
}
65+
66+
public Node getHead() {
67+
return head;
68+
}
69+
70+
public Node getTail() {
71+
return tail;
72+
}
73+
74+
public int getLength() {
75+
return length;
76+
}
77+
78+
public boolean isEmpty() {
79+
return length == 0;
80+
}
81+
82+
public void insertAtHead(int value) {
83+
insertNode(null, new Node(value), head);
84+
}
85+
86+
public void insertAtTail(int value) {
87+
insertNode(tail, new Node(value), null);
88+
}
89+
90+
public void insertAt(int value, int index) {
91+
if (index > length || index < 0) {
92+
throw new IndexOutOfBoundsException("index of " + index + " is out of bounds");
93+
}
94+
95+
Node node = new Node(value);
96+
Node previousNode = null;
97+
Node currentNodeAtIndex = head;
98+
for (int i = 0; i < index; i++) {
99+
previousNode = currentNodeAtIndex;
100+
currentNodeAtIndex = currentNodeAtIndex.next;
101+
}
102+
insertNode(previousNode, node, currentNodeAtIndex);
103+
}
104+
105+
public void removeFirstOccurrence(int value) {
106+
Node currentNode = head;
107+
while (currentNode != null) {
108+
if (currentNode.value == value) {
109+
removeNode(currentNode);
110+
return;
111+
}
112+
currentNode = currentNode.next;
113+
}
114+
}
115+
116+
public void removeAt(int index) {
117+
if (index >= length || index < 0) {
118+
throw new IndexOutOfBoundsException("index of " + index + " is out of bounds");
119+
}
120+
121+
Node currentNodeAtIndex = head;
122+
for (int i = 0; i < index; i++) {
123+
currentNodeAtIndex = currentNodeAtIndex.next;
124+
}
125+
126+
removeNode(currentNodeAtIndex);
127+
}
128+
129+
public void removeHead() {
130+
removeNode(head);
131+
}
132+
133+
public void removeTail() {
134+
removeNode(tail);
135+
}
136+
137+
private void removeNode(Node node) {
138+
if (node.previous == null) {
139+
head = node.next;
140+
}
141+
142+
if (node.next == null) {
143+
tail = node.previous;
144+
}
145+
146+
if (node.previous != null) {
147+
node.previous.next = node.next;
148+
}
149+
150+
if (node.next != null) {
151+
node.next.previous = node.previous;
152+
}
153+
154+
length--;
155+
}
156+
157+
private void insertNode(Node nodeBefore, Node node, Node nodeAfter) {
158+
node.next = nodeAfter;
159+
node.previous = nodeBefore;
160+
161+
if (nodeBefore == null) {
162+
head = node;
163+
}
164+
165+
if (nodeAfter == null) {
166+
tail = node;
167+
}
168+
169+
if (nodeBefore != null) {
170+
nodeBefore.next = node;
171+
}
172+
173+
if (nodeAfter != null) {
174+
nodeAfter.previous = node;
175+
}
176+
177+
length++;
178+
}
179+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
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;
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+
public void removeHead() {
97+
removeNode(head);
98+
}
99+
100+
public void removeTail() {
101+
removeNode(tail);
102+
}
103+
104+
private void removeNode(Node node) {
105+
if (node.previous == null) {
106+
head = node.next;
107+
}
108+
109+
if (node.next == null) {
110+
tail = node.previous;
111+
}
112+
113+
if (node.previous != null) {
114+
node.previous.next = node.next;
115+
}
116+
117+
if (node.next != null) {
118+
node.next.previous = node.previous;
119+
}
120+
121+
length--;
122+
}
123+
124+
private void insertNode(Node nodeBefore, Node node, Node nodeAfter) {
125+
node.next = nodeAfter;
126+
node.previous = nodeBefore;
127+
128+
if (nodeBefore == null) {
129+
head = node;
130+
}
131+
132+
if (nodeAfter == null) {
133+
tail = node;
134+
}
135+
136+
if (nodeBefore != null) {
137+
nodeBefore.next = node;
138+
}
139+
140+
if (nodeAfter != null) {
141+
nodeAfter.previous = node;
142+
}
143+
144+
length++;
145+
}
146+
}

0 commit comments

Comments
 (0)