-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSinglyLinkedList.js
279 lines (246 loc) · 6.93 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
/* 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.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
}
// 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)
}
let { currentNode } = this.initiateNodeAndIndex()
// Loop till there is a node present in the list
while (currentNode.next) {
currentNode = currentNode.next
}
const node = new Node(element)
// Adding node at the end of the list and increase the length
currentNode.next = node
this.length++
return this.size()
}
// add a node at first it to linklist
addFirst (element) {
const node = new Node(element)
node.next = this.headNode
this.headNode = node
this.length++
return this.size()
}
// remove the first from the linklist
removeFirst () {
const removedNode = this.headNode
if (this.length > 0) {
this.headNode = this.headNode.next
this.length--
}
return removedNode?.data
}
// remove the last from the linklist
removeLast () {
if (this.isEmpty()) return null
if (this.length === 1) {
return this.removeFirst()
}
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
while (currentIndex !== this.length - 2) {
currentIndex++
currentNode = currentNode.next
}
const removedNode = currentNode.next
currentNode.next = null
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 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--
break
}
currentNode = currentNode.next
}
return removedNode?.data || null
}
// Returns the index of the element passed as param otherwise -1
indexOf (element) {
let { currentIndex, currentNode } = this.initiateNodeAndIndex()
while (currentNode) {
// Checking if the node is the element we are searching for
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) 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
// Decrementing the length
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.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) {
let i = 0
let current = this.headNode
while (current) {
i++
current = current.next
}
k %= i
current = this.headNode
let prev = null
while (k--) {
if (!current || !current.next) {
return current
} else {
while (current.next) {
prev = current
current = current.next
}
prev.next = current.next
current.next = this.headNode
this.headNode = current
}
}
}
// 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))
}
}
export { Node, LinkedList }