131 lines
3.1 KiB
JavaScript
131 lines
3.1 KiB
JavaScript
|
const head = Symbol("head");
|
||
|
const tail = Symbol("tail");
|
||
|
|
||
|
class CircularDoublyLinkedListNode {
|
||
|
constructor (data) {
|
||
|
this.data = data;
|
||
|
this.next = null;
|
||
|
this.previous = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export class CircularDoublyLinkedList {
|
||
|
constructor () {
|
||
|
this[head] = null;
|
||
|
this[tail] = null;
|
||
|
}
|
||
|
|
||
|
add (data) {
|
||
|
const newNode = new CircularDoublyLinkedListNode(data);
|
||
|
|
||
|
// Special case: no items in the list
|
||
|
if (this[head] === null) {
|
||
|
this[head] = newNode;
|
||
|
newNode.next = newNode;
|
||
|
newNode.previous = newNode;
|
||
|
} else {
|
||
|
const tail = this[head].previous;
|
||
|
|
||
|
tail.next = newNode;
|
||
|
newNode.previous = tail;
|
||
|
newNode.next = this[head];
|
||
|
this[head].previous = newNode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
get (index) {
|
||
|
if ( ! Number(index) < 0) {
|
||
|
return undefined;
|
||
|
}
|
||
|
|
||
|
let current = this[head];
|
||
|
let i = 0;
|
||
|
|
||
|
do {
|
||
|
if (i === index) {
|
||
|
return current.data;
|
||
|
}
|
||
|
|
||
|
current = current.next;
|
||
|
i++;
|
||
|
} while ((current !== this[head]) && (i <= index));
|
||
|
|
||
|
return undefined;
|
||
|
}
|
||
|
|
||
|
remove (index) {
|
||
|
if ((this[head] === null) || (index < 0)) {
|
||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||
|
}
|
||
|
|
||
|
let current = this[head];
|
||
|
|
||
|
// Removing the first node
|
||
|
if (index === 0) {
|
||
|
if (current.next === this[head]) {
|
||
|
this[head] = null;
|
||
|
} else {
|
||
|
const tail = this[head].previous;
|
||
|
|
||
|
// Set the tail to point to the second item in the list
|
||
|
// and point the new item to the tail
|
||
|
tail.next = current.next;
|
||
|
current.next.previous = tail;
|
||
|
|
||
|
this[head] = tail.next;
|
||
|
}
|
||
|
|
||
|
return current.data;
|
||
|
}
|
||
|
|
||
|
let i = 0;
|
||
|
|
||
|
do {
|
||
|
current = current.next;
|
||
|
i++;
|
||
|
} while ((current !== this[head]) && (i < index));
|
||
|
|
||
|
if (current !== this[head]) {
|
||
|
// skip over the node to remove it
|
||
|
current.previous.next = current.next;
|
||
|
current.next.previous = current.previous;
|
||
|
|
||
|
return current.data;
|
||
|
}
|
||
|
|
||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||
|
}
|
||
|
|
||
|
*values () {
|
||
|
// list is empty
|
||
|
if (this[head] !== null) {
|
||
|
// only one node
|
||
|
if (this[head].next === this[head]) {
|
||
|
yield this[head].data;
|
||
|
} else {
|
||
|
let current = this[head];
|
||
|
|
||
|
do {
|
||
|
yield current.data;
|
||
|
current = current.next;
|
||
|
} while (current !== this[head]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*circularValues () {
|
||
|
if (this[head] !== null) {
|
||
|
let current = this[head];
|
||
|
|
||
|
// infinite loop
|
||
|
while (true) {
|
||
|
yield current.data;
|
||
|
current = current.next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Symbol.iterator] () {
|
||
|
return this.values();
|
||
|
}
|
||
|
}
|