1
+ import LinkedListNode from './LinkedListNode' ;
2
+ import Comparator from './Comparator' ;
3
+
4
+ export default class LinkedList {
5
+ /**
6
+ * @param {Function } [comparatorFunction]
7
+ */
8
+ constructor ( comparatorFunction ) {
9
+ /** @var LinkedListNode */
10
+ this . head = null ;
11
+
12
+ /** @var LinkedListNode */
13
+ this . tail = null ;
14
+
15
+ this . compare = new Comparator ( comparatorFunction ) ;
16
+ }
17
+
18
+ /**
19
+ * @param {* } value
20
+ * @return {LinkedList }
21
+ */
22
+ prepend ( value ) {
23
+ // Make new node to be a head.
24
+ const newNode = new LinkedListNode ( value , this . head ) ;
25
+ this . head = newNode ;
26
+
27
+ // If there is no tail yet let's make new node a tail.
28
+ if ( ! this . tail ) {
29
+ this . tail = newNode ;
30
+ }
31
+
32
+ return this ;
33
+ }
34
+
35
+ /**
36
+ * @param {* } value
37
+ * @return {LinkedList }
38
+ */
39
+ append ( value ) {
40
+ const newNode = new LinkedListNode ( value ) ;
41
+
42
+ // If there is no head yet let's make new node a head.
43
+ if ( ! this . head ) {
44
+ this . head = newNode ;
45
+ this . tail = newNode ;
46
+
47
+ return this ;
48
+ }
49
+
50
+ // Attach new node to the end of linked list.
51
+ this . tail . next = newNode ;
52
+ this . tail = newNode ;
53
+
54
+ return this ;
55
+ }
56
+
57
+ /**
58
+ * @param {* } value
59
+ * @return {LinkedListNode }
60
+ */
61
+ delete ( value ) {
62
+ if ( ! this . head ) {
63
+ return null ;
64
+ }
65
+
66
+ let deletedNode = null ;
67
+
68
+ // If the head must be deleted then make next node that is different
69
+ // from the head to be a new head.
70
+ while ( this . head && this . compare . equal ( this . head . value , value ) ) {
71
+ deletedNode = this . head ;
72
+ this . head = this . head . next ;
73
+ }
74
+
75
+ let currentNode = this . head ;
76
+
77
+ if ( currentNode !== null ) {
78
+ // If next node must be deleted then make next node to be a next next one.
79
+ while ( currentNode . next ) {
80
+ if ( this . compare . equal ( currentNode . next . value , value ) ) {
81
+ deletedNode = currentNode . next ;
82
+ currentNode . next = currentNode . next . next ;
83
+ } else {
84
+ currentNode = currentNode . next ;
85
+ }
86
+ }
87
+ }
88
+
89
+ // Check if tail must be deleted.
90
+ if ( this . compare . equal ( this . tail . value , value ) ) {
91
+ this . tail = currentNode ;
92
+ }
93
+
94
+ return deletedNode ;
95
+ }
96
+
97
+ /**
98
+ * @param {Object } findParams
99
+ * @param {* } findParams.value
100
+ * @param {function } [findParams.callback]
101
+ * @return {LinkedListNode }
102
+ */
103
+ find ( { value = undefined , callback = undefined } ) {
104
+ if ( ! this . head ) {
105
+ return null ;
106
+ }
107
+
108
+ let currentNode = this . head ;
109
+
110
+ while ( currentNode ) {
111
+ // If callback is specified then try to find node by callback.
112
+ if ( callback && callback ( currentNode . value ) ) {
113
+ return currentNode ;
114
+ }
115
+
116
+ // If value is specified then try to compare by value..
117
+ if ( value !== undefined && this . compare . equal ( currentNode . value , value ) ) {
118
+ return currentNode ;
119
+ }
120
+
121
+ currentNode = currentNode . next ;
122
+ }
123
+
124
+ return null ;
125
+ }
126
+
127
+ /**
128
+ * @return {LinkedListNode }
129
+ */
130
+ deleteTail ( ) {
131
+ const deletedTail = this . tail ;
132
+
133
+ if ( this . head === this . tail ) {
134
+ // There is only one node in linked list.
135
+ this . head = null ;
136
+ this . tail = null ;
137
+
138
+ return deletedTail ;
139
+ }
140
+
141
+ // If there are many nodes in linked list...
142
+
143
+ // Rewind to the last node and delete "next" link for the node before the last one.
144
+ let currentNode = this . head ;
145
+ while ( currentNode . next ) {
146
+ if ( ! currentNode . next . next ) {
147
+ currentNode . next = null ;
148
+ } else {
149
+ currentNode = currentNode . next ;
150
+ }
151
+ }
152
+
153
+ this . tail = currentNode ;
154
+
155
+ return deletedTail ;
156
+ }
157
+
158
+ /**
159
+ * @return {LinkedListNode }
160
+ */
161
+ deleteHead ( ) {
162
+ if ( ! this . head ) {
163
+ return null ;
164
+ }
165
+
166
+ const deletedHead = this . head ;
167
+
168
+ if ( this . head . next ) {
169
+ this . head = this . head . next ;
170
+ } else {
171
+ this . head = null ;
172
+ this . tail = null ;
173
+ }
174
+
175
+ return deletedHead ;
176
+ }
177
+
178
+ /**
179
+ * @param {*[] } values - Array of values that need to be converted to linked list.
180
+ * @return {LinkedList }
181
+ */
182
+ fromArray ( values ) {
183
+ values . forEach ( ( value ) => this . append ( value ) ) ;
184
+
185
+ return this ;
186
+ }
187
+
188
+ /**
189
+ * @return {LinkedListNode[] }
190
+ */
191
+ toArray ( ) {
192
+ const nodes = [ ] ;
193
+
194
+ let currentNode = this . head ;
195
+ while ( currentNode ) {
196
+ nodes . push ( currentNode ) ;
197
+ currentNode = currentNode . next ;
198
+ }
199
+
200
+ return nodes ;
201
+ }
202
+
203
+ /**
204
+ * @param {function } [callback]
205
+ * @return {string }
206
+ */
207
+ toString ( callback ) {
208
+ return this . toArray ( ) . map ( ( node ) => node . toString ( callback ) ) . toString ( ) ;
209
+ }
210
+
211
+ /**
212
+ * Reverse a linked list.
213
+ * @returns {LinkedList }
214
+ */
215
+ reverse ( ) {
216
+ let currNode = this . head ;
217
+ let prevNode = null ;
218
+ let nextNode = null ;
219
+
220
+ while ( currNode ) {
221
+ // Store next node.
222
+ nextNode = currNode . next ;
223
+
224
+ // Change next node of the current node so it would link to previous node.
225
+ currNode . next = prevNode ;
226
+
227
+ // Move prevNode and currNode nodes one step forward.
228
+ prevNode = currNode ;
229
+ currNode = nextNode ;
230
+ }
231
+
232
+ // Reset head and tail.
233
+ this . tail = this . head ;
234
+ this . head = prevNode ;
235
+
236
+ return this ;
237
+ }
238
+ }
239
+ // 兆易创新/紫光国微,复星医药/新和成,迈瑞医疗,隆基股份/金风科技,国轩高科/阳光电源
0 commit comments