1
1
package section23 ;
2
2
3
+ import java .util .LinkedList ;
4
+ import java .util .Queue ;
5
+ import java .util .Stack ;
6
+ import java .util .function .Function ;
7
+
3
8
/**
4
9
* 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.
5
12
*/
6
13
public class ImmutableList <T > {
7
14
@@ -31,14 +38,14 @@ public ImmutableList(Node<T> head) {
31
38
this .head = head ;
32
39
}
33
40
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) */
35
42
public ImmutableList <T > cons (T val ) {
36
43
Node <T > newHead = new Node <T >(val , head );
37
44
ImmutableList <T > newList = new ImmutableList <>(newHead );
38
45
return newList ;
39
46
}
40
47
41
- /* Utility method that returns the length of linked list */
48
+ /* Utility method that returns the length of linked list - O(n) */
42
49
public int length () {
43
50
int result = 0 ;
44
51
Node <T > iter = head ;
@@ -50,24 +57,98 @@ public int length() {
50
57
return result ;
51
58
}
52
59
53
- /* Returns an element of the linked list by index */
60
+ /* Returns an element of the linked list by index - O(n) */
54
61
public T get (int idx ) {
55
62
if (idx < 0 ) {
56
63
throw new IndexOutOfBoundsException ("negative index" );
57
64
}
58
65
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 ;
60
126
}
61
127
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 ;
66
136
}
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 (" - " );
71
149
}
150
+
151
+ resultBuffer .delete (resultBuffer .length () - 3 , resultBuffer .length ()).append (")" );
152
+ return resultBuffer .toString ();
72
153
}
73
- }
154
+ }
0 commit comments