@vanillaes/computer-science
Version:
Algorithms and Data Structures implemented in modern JS
141 lines (125 loc) • 2.93 kB
JavaScript
/** A LinkedList implementation using nodes liked by reference */
export class LinkedList {
/**
* The head node in the list
* @private
* @type {Object}
*/
#head = null
/**
* The tail node in the list
* @private
* @type {Object}
*/
#tail = null
/**
* The number of items in the list
* @type {number}
*/
size = 0
/**
* @param {array} [items] an array of items to add to the list
*/
constructor (items) {
if (items) {
this.addAll(items)
}
}
/**
* Add an item to the list
*
* @param {*} item an item to add to the list
*/
add (item = null) {
if (item === null) { throw Error('\'item\' parameter not defined') }
if (this.size === 0) {
this.#tail = new ListNode(item, null)
this.#head = this.#tail
} else {
const prev = this.#tail
this.#tail = new ListNode(item, null)
prev.next = this.#tail
}
this.size++
}
/**
* Add multiple items to the list
*
* @param {*[]} items an array of items to be added to the list
*/
addAll (items = null) {
if (items === null) { throw Error('\'items\' parameter not defined') }
items.forEach(item => this.add(item))
}
/**
* Remove an item from the list
*
* @param {*} item the item to remove from the list
* @returns {boolean} true if the item was successfully removed, false if not
*/
remove (item = null) {
if (item === null) { throw Error('\'item\' parameter not defined') }
if (this.size === 0) { throw Error('can\'t remove an item from an empty list') }
let prev = this.#head
let curr = this.#head
while (curr != null) {
if (curr.data === item) {
if (this.size === 1) { // remove the last remaining element
this.#head = null
this.tail = null
} else if (curr === this.#head) { // remove first element
this.#head = this.#head.next
} else if (curr === this.#tail) { // remove last element
this.#tail = prev
this.#tail.next = null
} else { // remove element
prev.next = curr.next
}
this.size--
return true
}
prev = curr
curr = prev.next
}
return false
}
/**
* Remove all items from the list
* @method
*/
clear () {
this.#head = null
this.#tail = null
this.size = 0
}
/**
* Iterate all items (in-order) in the list
*
* @private
* @returns {Iterator<*>} an iterator for the data
*/
[Symbol.iterator] () {
let item = this.#head
return {
next: () => {
if (item) {
const value = item.data
item = item.next
return { value, done: false }
}
return { value: null, done: true }
}
}
}
}
/**
* @private
*/
class ListNode {
data
next
constructor (data, next = null) {
this.data = data
this.next = next
}
}