Skip to content

Commit 2a9e3d9

Browse files
committed
implement immutable linked list (untested)
1 parent 302c5cc commit 2a9e3d9

File tree

2 files changed

+107
-13
lines changed

2 files changed

+107
-13
lines changed

src/section23/ImmutableList.java

+94-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package section23;
22

3+
import java.util.LinkedList;
4+
import java.util.Queue;
5+
import java.util.Stack;
6+
import java.util.function.Function;
7+
38
/**
49
* This class implements a generic immutable Linked List that demonstrates the advantages of immutable data structures.
10+
*
11+
* Despite that functional programming favors recursion, all recursions in this example are unwrapped to optimize perf.
512
*/
613
public class ImmutableList<T> {
714

@@ -31,14 +38,14 @@ public ImmutableList(Node<T> head) {
3138
this.head = head;
3239
}
3340

34-
/* Prepends a value to the linked list, and returns a new immutable linked list */
41+
/* Prepends a value to the linked list, and returns a new immutable linked list - O(1) */
3542
public ImmutableList<T> cons(T val) {
3643
Node<T> newHead = new Node<T>(val, head);
3744
ImmutableList<T> newList = new ImmutableList<>(newHead);
3845
return newList;
3946
}
4047

41-
/* Utility method that returns the length of linked list */
48+
/* Utility method that returns the length of linked list - O(n) */
4249
public int length() {
4350
int result = 0;
4451
Node<T> iter = head;
@@ -50,24 +57,98 @@ public int length() {
5057
return result;
5158
}
5259

53-
/* Returns an element of the linked list by index */
60+
/* Returns an element of the linked list by index - O(n) */
5461
public T get(int idx) {
5562
if (idx < 0) {
5663
throw new IndexOutOfBoundsException("negative index");
5764
}
5865

59-
return getFromNode(head, idx);
66+
int steps = idx;
67+
Node<T> iter = head;
68+
while (steps > 0) {
69+
if (iter == null) {
70+
throw new IndexOutOfBoundsException("idx = " + idx);
71+
}
72+
iter = iter.next;
73+
steps--;
74+
}
75+
76+
if (iter == null) {
77+
throw new IndexOutOfBoundsException("idx = " + idx);
78+
}
79+
return iter.data;
80+
}
81+
82+
/* Applies a transformation function to all elements of the linked list and return a new immutable list */
83+
public <W> ImmutableList<W> map(Function<T, W> fn) {
84+
Stack<W> mappedValues = new Stack<>();
85+
Node<T> iter = head;
86+
87+
while (iter != null) {
88+
mappedValues.push(fn.apply(iter.data));
89+
}
90+
91+
ImmutableList<W> result = new ImmutableList<>();
92+
while (!mappedValues.isEmpty()) {
93+
result = result.cons(mappedValues.pop());
94+
}
95+
return result;
96+
}
97+
98+
/* Inserts an element to selected index and returns a new immutable list */
99+
public ImmutableList<T> insert(T elem, int idx) {
100+
if (idx < 0) {
101+
throw new IndexOutOfBoundsException("negative index");
102+
}
103+
104+
int steps = idx;
105+
Node<T> iter = head;
106+
Stack<T> prefix = new Stack<>();
107+
108+
while (steps > 0) {
109+
if (iter == null) {
110+
throw new IndexOutOfBoundsException("idx = " + idx);
111+
}
112+
prefix.push(iter.data);
113+
iter = iter.next;
114+
steps--;
115+
}
116+
117+
// insert the element
118+
ImmutableList<T> result = new ImmutableList<>(new Node<>(elem, iter));
119+
120+
// add in original prefix
121+
while (!prefix.isEmpty()) {
122+
result = result.cons(prefix.pop());
123+
}
124+
125+
return result;
60126
}
61127

62-
/* Helper recursive method that returns the content of a node based on head and offset idx */
63-
private static <T> T getFromNode(Node<T> head, int idx) {
64-
if (head == null) {
65-
throw new IndexOutOfBoundsException("index overflow");
128+
/* Return a new immutable list that is the reverse of current list */
129+
public ImmutableList<T> revert() {
130+
ImmutableList<T> result = new ImmutableList<>();
131+
132+
Node<T> iter = head;
133+
while (iter != null) {
134+
result = result.cons(iter.data);
135+
iter = iter.next;
66136
}
67-
if (idx == 0) {
68-
return head.data;
69-
} else {
70-
return getFromNode(head.next, idx - 1);
137+
138+
return result;
139+
}
140+
141+
/* Returns a String representation of the linked list */
142+
public String toString() {
143+
StringBuilder resultBuffer = new StringBuilder("ImmutableList(");
144+
145+
Node<T> node = head;
146+
while (node != null) {
147+
resultBuffer.append(node.data);
148+
resultBuffer.append(" - ");
71149
}
150+
151+
resultBuffer.delete(resultBuffer.length() - 3, resultBuffer.length()).append(")");
152+
return resultBuffer.toString();
72153
}
73-
}
154+
}

src/section23/ImmutableListTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package section23;
2+
3+
/**
4+
* This class includes comprehensive tests for the immutable linked list in section23.ImmutableList.
5+
* All core methods in ImmutableList are covered by the following tests.
6+
*/
7+
public class ImmutableListTest {
8+
9+
public static void main(String[] argv) {
10+
11+
}
12+
13+
}

0 commit comments

Comments
 (0)