1
1
import { LinkedListNode } from './linked-list-node' ;
2
+ import { Comparator } from '../utils/comparator' ;
3
+ import type { IComparator , CompareFunction } from '../utils/comparator' ;
2
4
3
5
type NullableLinkedListNode < T = any > = LinkedListNode < T > | null ;
4
6
type FindMethodOptions < T = any > = {
@@ -12,29 +14,34 @@ export interface ILinkedList<T = any> {
12
14
readonly length : number ;
13
15
readonly isEmpty : boolean ;
14
16
17
+ append ( value : T ) : this;
18
+ fromArray ( array : T [ ] ) : this;
15
19
toArray ( ) : T [ ] ;
16
20
toString ( ) : string ;
17
- append ( value : T ) : this;
18
21
prepend ( value : T ) : this;
19
- reverse ( ) : this;
20
22
delete ( value : T ) : NullableLinkedListNode < T > ;
23
+ reverse ( ) : this;
21
24
insertAt ( index : number , value : T ) : this;
22
25
deleteHead ( ) : NullableLinkedListNode < T > ;
23
26
deleteTail ( ) : NullableLinkedListNode < T > ;
24
27
indexOf ( value : T ) : number ;
25
- fromArray ( array : T [ ] ) : this;
26
28
find ( options : FindMethodOptions < T > ) : NullableLinkedListNode < T > ;
27
29
}
28
30
29
31
export class LinkedList < T = any > implements ILinkedList < T > {
30
- #head: NullableLinkedListNode < T > = null ;
32
+ #head: NullableLinkedListNode < T > ;
31
33
32
- #tail: NullableLinkedListNode < T > = null ;
34
+ #tail: NullableLinkedListNode < T > ;
33
35
34
- #length: number = 0 ;
36
+ #length: number ;
35
37
36
- get isEmpty ( ) {
37
- return this . #head === null ;
38
+ #compare: IComparator < T > ;
39
+
40
+ constructor ( compareFunction ?: CompareFunction < T > ) {
41
+ this . #head = null ;
42
+ this . #tail = null ;
43
+ this . #length = 0 ;
44
+ this . #compare = new Comparator ( compareFunction ) ;
38
45
}
39
46
40
47
get head ( ) {
@@ -45,24 +52,12 @@ export class LinkedList<T = any> implements ILinkedList<T> {
45
52
return this . #tail;
46
53
}
47
54
48
- get length ( ) : number {
55
+ get length ( ) {
49
56
return this . #length;
50
57
}
51
58
52
- toArray ( ) {
53
- const array = [ ] ;
54
- let currentNode = this . #head;
55
-
56
- while ( currentNode ) {
57
- array . push ( currentNode . value ) ;
58
- currentNode = currentNode . next ;
59
- }
60
-
61
- return array ;
62
- }
63
-
64
- toString ( ) {
65
- return this . toArray ( ) . toString ( ) ;
59
+ get isEmpty ( ) {
60
+ return this . #head === null ;
66
61
}
67
62
68
63
append ( value : T ) {
@@ -81,6 +76,30 @@ export class LinkedList<T = any> implements ILinkedList<T> {
81
76
return this ;
82
77
}
83
78
79
+ fromArray ( array : T [ ] ) {
80
+ array . forEach ( ( value ) => {
81
+ this . append ( value ) ;
82
+ } ) ;
83
+
84
+ return this ;
85
+ }
86
+
87
+ toArray ( ) {
88
+ const array = [ ] ;
89
+ let currentNode = this . #head;
90
+
91
+ while ( currentNode ) {
92
+ array . push ( currentNode . value ) ;
93
+ currentNode = currentNode . next ;
94
+ }
95
+
96
+ return array ;
97
+ }
98
+
99
+ toString ( ) {
100
+ return this . toArray ( ) . toString ( ) ;
101
+ }
102
+
84
103
prepend ( value : T ) {
85
104
const newNode = new LinkedListNode ( value ) ;
86
105
@@ -102,29 +121,32 @@ export class LinkedList<T = any> implements ILinkedList<T> {
102
121
103
122
let deletedNode = null as NullableLinkedListNode ;
104
123
105
- // Delete from the beginning of the list
106
- if ( value === this . #head. value ) {
124
+ // Delete from the beginning of the list.
125
+ if ( this . #compare . equal ( value , this . #head. value ) ) {
107
126
deletedNode = this . #head;
108
127
this . #head = deletedNode . next ;
109
128
110
- // Update tail if the list becomes empty
129
+ // Update tail if the list becomes empty.
111
130
if ( this . #head === null ) {
112
131
this . #tail = null ;
113
132
}
114
133
} else {
115
134
let currentNode = this . #head;
116
135
117
- // Search for the node by value
118
- while ( currentNode . next && value !== currentNode . next . value ) {
136
+ // Search for the node by value.
137
+ while (
138
+ currentNode . next &&
139
+ ! this . #compare. equal ( value , currentNode . next . value )
140
+ ) {
119
141
currentNode = currentNode . next ;
120
142
}
121
143
122
- // Delete the node from the middle
144
+ // Delete the node from the middle.
123
145
if ( currentNode . next !== null ) {
124
146
deletedNode = currentNode . next ;
125
147
currentNode . next = deletedNode ?. next ;
126
148
127
- // Update tail if the last node is deleted
149
+ // Update tail if the last node is deleted.
128
150
if ( currentNode . next === null ) {
129
151
this . #tail = currentNode ;
130
152
}
@@ -139,14 +161,17 @@ export class LinkedList<T = any> implements ILinkedList<T> {
139
161
}
140
162
141
163
reverse ( ) {
142
- if ( this . #head === null || this . #head. next === null ) return this ;
164
+ if ( this . #head === null || this . #head. next === null ) {
165
+ return this ;
166
+ }
143
167
144
168
let currentNode = this . #head as NullableLinkedListNode ;
145
169
let prevNode = null ;
146
170
147
- while ( currentNode ) {
171
+ while ( currentNode !== null ) {
148
172
const nextNode = currentNode . next ;
149
- [ currentNode . next , prevNode ] = [ prevNode , currentNode ] ;
173
+ currentNode . next = prevNode ;
174
+ prevNode = currentNode ;
150
175
151
176
currentNode = nextNode ;
152
177
}
@@ -168,20 +193,22 @@ export class LinkedList<T = any> implements ILinkedList<T> {
168
193
}
169
194
170
195
insertAt ( index : number , value : T ) : this {
171
- if ( index < 0 || index > this . #length) {
196
+ const isInvalidIndex = index < 0 || index > this . #length;
197
+
198
+ if ( isInvalidIndex ) {
172
199
throw new Error (
173
200
'Index should be greater than or equal to 0 and less than or equal to the list length.' ,
174
201
) ;
175
202
}
176
203
177
204
if ( index === 0 ) {
178
- // Insert at the beginning
205
+ // Insert at the beginning.
179
206
this . prepend ( value ) ;
180
207
} else if ( index === this . #length) {
181
- // Insert end
208
+ // Insert at the end.
182
209
this . append ( value ) ;
183
210
} else {
184
- // Insert in the middle
211
+ // Insert in the middle.
185
212
const prevNode = this . #findNodeByIndex( index - 1 ) ;
186
213
const newNode = new LinkedListNode ( value ) ;
187
214
@@ -199,8 +226,8 @@ export class LinkedList<T = any> implements ILinkedList<T> {
199
226
200
227
const deletedNode = this . #head;
201
228
202
- if ( this . #head ?. next ) {
203
- this . #head = this . #head . next ;
229
+ if ( deletedNode ?. next ) {
230
+ this . #head = deletedNode . next ;
204
231
} else {
205
232
this . #head = null ;
206
233
this . #tail = null ;
@@ -239,10 +266,10 @@ export class LinkedList<T = any> implements ILinkedList<T> {
239
266
240
267
indexOf ( value : T ) {
241
268
let count = 0 ;
242
- let currentNode = this . head ;
269
+ let currentNode = this . # head;
243
270
244
- while ( currentNode ) {
245
- if ( value === currentNode . value ) return count ;
271
+ while ( currentNode !== null ) {
272
+ if ( this . #compare . equal ( value , currentNode . value ) ) return count ;
246
273
247
274
currentNode = currentNode . next ;
248
275
count += 1 ;
@@ -251,25 +278,17 @@ export class LinkedList<T = any> implements ILinkedList<T> {
251
278
return - 1 ;
252
279
}
253
280
254
- fromArray ( array : T [ ] ) {
255
- array . forEach ( ( value ) => {
256
- this . append ( value ) ;
257
- } ) ;
258
-
259
- return this ;
260
- }
261
-
262
281
find ( { value, predicate } : FindMethodOptions < T > ) {
263
282
if ( this . #head === null ) return null ;
264
283
265
- let currentNode = this . head as NullableLinkedListNode ;
284
+ let currentNode = this . # head as NullableLinkedListNode ;
266
285
267
286
while ( currentNode ) {
268
287
if ( predicate && predicate ( currentNode . value ) ) {
269
288
return currentNode ;
270
289
}
271
290
272
- if ( value !== undefined && value === currentNode . value ) {
291
+ if ( value && this . #compare . equal ( value , currentNode . value ) ) {
273
292
return currentNode ;
274
293
}
275
294
0 commit comments