forked from TheAlgorithms/JavaScript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SinglyLinkedList.js
305 lines (274 loc) · 7.65 KB
/
SinglyLinkedList.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/* SinglyLinkedList!!
* A linked list is similar to an array, it holds a list of values.
* However, links in a linked list do not have indexes. With
* a linked list you do not need to predetermine its size as
* it grows and shrinks as it is edited. This is an example of
* a singly linked list.
*/
// Methods - size, head, addLast, addFirst, addAt, removeFirst, removeLast, remove, removeAt, indexOf, isEmpty, elementAt, findMiddle, get, clean, rotateListRight
class Node {
constructor (data) {
this.data = data
this.next = null
}
}
class LinkedList {
constructor (listOfValues) {
this.headNode = null
this.tailNode = null
this.length = 0
if (listOfValues instanceof Array) {
for (const value of listOfValues) {
this.addLast(value)
}
}
}
// initiates the currentNode and currentIndex and return as an object
initiateNodeAndIndex () {
return { currentNode: this.headNode, currentIndex: 0 }
}
// Returns length
size () {
return this.length
}
// Returns the head
head () {
return this.headNode?.data || null
}
// Returns the tail
tail () {
return this.tailNode?.data || null
}
// Return if the list is empty
isEmpty () {
return this.length === 0
}
// add a node at last it to linklist
addLast (element) {
// Check if its the first element
if (this.headNode === null) {
return this.addFirst(element)
}
const node = new Node(element)
// Adding node at the end of the list and increase the length
this.tailNode.next = node
this.tailNode = node
this.length++
return this.size()
}
// add a node at first it to linklist
addFirst (element) {
const node = new Node(element)
// Check if its the first element
if (this.headNode === null) {
this.tailNode = node
}
// Adding node at the start of the list and increase the length
node.next = this.headNode
this.headNode = node
this.length++
return this.size()
}
// remove the first from the linklist
removeFirst () {
// Check if head is null
if (this.headNode === null) {
return null
}
// Removing node at the start of the list and decrease the length
const removedNode = this.headNode
this.headNode = this.headNode.next
this.length--
// Check if the list is empty
if (this.isEmpty()) {
this.tailNode = null
}
return removedNode?.data
}
// remove the last from the linklist
removeLast () {
if (this.isEmpty()) return null
// Check if there is only one element
if (this.length === 1) {
return this.removeFirst()
}
// Removing node at the end of the list and decrease the length
const removedNode = this.tailNode
let { currentNode } = this.initiateNodeAndIndex()
while (currentNode.next.next) {
currentNode = currentNode.next
}
currentNode.next = null
this.tailNode = currentNode
this.length--
return removedNode.data
}
// Removes the node with the value as param
remove (element) {
if (this.isEmpty()) return null
let { currentNode } = this.initiateNodeAndIndex()
let removedNode = null
// Check if the head node is the element to remove
if (currentNode.data === element) {
return this.removeFirst()
}
// Check if the tail node is the element to remove
if (this.tailNode.data === element) {
return this.removeLast()
}
// Check which node is the node to remove
while (currentNode.next) {
if (currentNode.next.data === element) {
removedNode = currentNode.next
currentNode.next = currentNode.next.next
this.length--
return removedNode.data
}
currentNode = currentNode.next
}
return removedNode?.data || null
}
// Returns the index of the element passed as param otherwise -1
indexOf (element) {
if (this.isEmpty()) return -1
let { currentNode, currentIndex } = this.initiateNodeAndIndex()
while (currentNode) {
if (currentNode.data === element) {
return currentIndex
}
currentNode = currentNode.next
currentIndex++
}
return -1
}
// Returns the element at an index
elementAt (index) {
if (index >= this.length || index < 0) {
throw new RangeError('Out of Range index')
}
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
while (currentIndex < index) {
currentIndex++
currentNode = currentNode.next
}
return currentNode.data
}
// Adds the element at specified index
addAt (index, element) {
// Check if index is out of bounds of list
if (index > this.length || index < 0) {
throw new RangeError('Out of Range index')
}
if (index === 0) return this.addFirst(element)
if (index === this.length) return this.addLast(element)
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
const node = new Node(element)
while (currentIndex !== index - 1) {
currentIndex++
currentNode = currentNode.next
}
// Adding the node at specified index
const tempNode = currentNode.next
currentNode.next = node
node.next = tempNode
// Incrementing the length
this.length++
return this.size()
}
// Removes the node at specified index
removeAt (index) {
// Check if index is present in list
if (index < 0 || index >= this.length) {
throw new RangeError('Out of Range index')
}
if (index === 0) return this.removeFirst()
if (index === this.length - 1) return this.removeLast()
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
while (currentIndex !== index - 1) {
currentIndex++
currentNode = currentNode.next
}
const removedNode = currentNode.next
currentNode.next = currentNode.next.next
this.length--
return removedNode.data
}
// Returns a reference to middle node of linked list
findMiddle () {
// If there are two middle nodes, return the second middle node.
let fast = this.headNode
let slow = this.headNode
while (fast !== null && fast.next !== null) {
fast = fast.next.next
slow = slow.next
}
return slow
}
// make the linkedList Empty
clean () {
this.headNode = null
this.tailNode = null
this.length = 0
}
// Method to get the LinkedList
get () {
const list = []
let { currentNode } = this.initiateNodeAndIndex()
while (currentNode) {
list.push(currentNode.data)
currentNode = currentNode.next
}
return list
}
// Method for Rotating a List to the right by k places
rotateListRight (k) {
if (!this.headNode) return
let current = this.headNode
let tail = this.tailNode
let count = 1
while (current.next) {
count++
current = current.next
}
current.next = this.headNode
tail = current
k %= count
while (count - k > 0) {
tail = tail.next
count--
}
this.headNode = tail.next
tail.next = null
}
// Method to iterate over the LinkedList
iterator () {
let { currentNode } = this.initiateNodeAndIndex()
if (currentNode === null) return -1
const iterate = function * () {
while (currentNode) {
yield currentNode.data
currentNode = currentNode.next
}
}
return iterate()
}
// Method to log the LinkedList
log () {
console.log(JSON.stringify(this.headNode, null, 2))
}
// Method to reverse the LinkedList
reverse () {
let head = this.headNode
let prev = null
let next = null
while (head) {
next = head.next
head.next = prev
prev = head
head = next
}
this.tailNode = this.headNode
this.headNode = prev
};
}
export { Node, LinkedList }