Last active
October 11, 2019 21:46
-
-
Save uhop/f17409a95a14f10e1cbd5a584ca9d245 to your computer and use it in GitHub Desktop.
Simple yet complete implementation of a double-linked list.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
class ListNode { | |
constructor() { | |
this.prev = this.next = this; | |
} | |
} | |
const pop = head => { | |
const rest = head.next; | |
head.prev.next = head.next; | |
head.next.prev = head.prev; | |
head.prev = head.next = head; | |
return {node: head, head: rest}; | |
}; | |
const extract = (from, to) => { | |
const prev = from.prev, | |
next = to.next; | |
prev.next = next; | |
next.prev = prev; | |
from.prev = to; | |
to.next = from; | |
return from; | |
}; | |
const splice = (head1, head2) => { | |
const tail1 = head1.prev, | |
tail2 = head2.prev; | |
tail1.next = head2; | |
head2.prev = tail1; | |
tail2.next = head1; | |
head1.prev = tail2; | |
return head1; | |
}; | |
class ListValueNode extends ListNode { | |
constructor(value) { | |
super(); | |
this.value = value; | |
} | |
pop() { | |
return pop(this).node.value; | |
} | |
addBefore(value) { | |
splice(this, new ListValueNode(value)); | |
return this; | |
} | |
addAfter(value) { | |
splice(this.next, new ListValueNode(value)); | |
return this; | |
} | |
insertBefore(list) { | |
splice(this, pop(list).head); | |
} | |
insertAfter(list) { | |
splice(this.next, pop(list).head); | |
} | |
} | |
class List extends ListNode { | |
get isEmpty() { | |
return this.prev === this; | |
} | |
get front() { | |
return this.next; | |
} | |
get back() { | |
return this.prev; | |
} | |
getLength() { | |
let n = 0; | |
for (let p = this.next; p !== this; ++n, p = p.next); | |
return n; | |
} | |
clear() { | |
this.prev = this.next = this; | |
return this; | |
} | |
remove(from, to = from) { | |
extract(from, to); | |
return this; | |
} | |
extract(from, to) { | |
return splice(new List(), extract(from, to)); | |
} | |
reverse() { | |
let next = this.next; | |
this.next = this.prev; | |
this.prev = next; | |
while (next !== this) { | |
const node = next; | |
next = node.next; | |
node.next = node.prev; | |
node.prev = next; | |
} | |
return this; | |
} | |
popFront() { | |
if (this.prev !== this) { | |
return this.next.pop(); | |
} | |
} | |
popBack() { | |
if (this.prev !== this) { | |
return this.prev.pop(); | |
} | |
} | |
pushFront(value) { | |
splice(this.next, new ListValueNode(value)); | |
return this; | |
} | |
pushBack(value) { | |
splice(this, new ListValueNode(value)); | |
return this; | |
} | |
appendFront(list) { | |
if (list.prev !== list) { | |
splice(this.next, extract(list.next, list.prev)); | |
} | |
return this; | |
} | |
appendBack(list) { | |
if (list.prev !== list) { | |
splice(this, extract(list.next, list.prev)); | |
} | |
return this; | |
} | |
moveToFront(node) { | |
if (this.next !== node) { | |
splice(this.next, extract(node, node)); | |
} | |
return this; | |
} | |
moveToBack(node) { | |
if (this.prev !== node) { | |
splice(this, extract(node, node)); | |
} | |
return this; | |
} | |
[Symbol.iterator]() { | |
let current = this.next; | |
return { | |
next: () => { | |
if (current === this) return {done: true}; | |
current = current.next; | |
return {value: current.prev.value}; | |
} | |
}; | |
} | |
getReverseIterable() { | |
return { | |
[Symbol.iterator]: () => { | |
let current = this.prev; | |
return { | |
next: () => { | |
if (current === this) return {done: true}; | |
current = current.prev; | |
return {value: current.next.value}; | |
} | |
}; | |
} | |
}; | |
} | |
static from(values) { | |
const list = new List(); | |
for (const value of values) { | |
list.pushBack(value); | |
} | |
return list; | |
} | |
} | |
module.exports = List; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment