@figliolia/data-structures
Version:
Efficient data structures for every day programming
123 lines (114 loc) • 2.44 kB
text/typescript
class ListNode<T> {
value: T;
previous: ListNode<T> | null = null;
next: ListNode<T> | null = null;
constructor(
value: T,
previous: ListNode<T> | null = null,
next: ListNode<T> | null = null,
) {
this.value = value;
this.next = next;
this.previous = previous;
}
}
/**
* Linked List
*
* A doubly linked list mimicking the interface of JavaScript arrays
*
* ```typescript
* import { LinkedList } from "@figliolia/data-structures";
*
* const list = new LinkedList<number>();
* list.push(1);
* list.push(2);
* list.push(3);
* for(const item of list) {
* console.log(item); // 1, 2, 3
* }
* list.pop(); // 3 -> O(1)
* list.shift() // 1 -> O(1)
* list.push(3) // O(1)
* list.unshift(1) // O(1)
* ```
*/
export class LinkedList<T> {
size = 0;
head: ListNode<T> | null = null;
tail: ListNode<T> | null = null;
constructor(...items: T[]) {
for (const item of items) {
this.push(item);
}
}
public push(item: T) {
this.size++;
const node = new ListNode(item);
if (!this.head && !this.tail) {
this.head = node;
this.tail = node;
return this.size;
}
this.tail!.next = node;
node.previous = this.tail;
this.tail = node;
return this.size;
}
public unshift(item: T) {
this.size++;
const node = new ListNode(item);
if (!this.head && !this.tail) {
this.head = node;
this.tail = node;
return this.size;
}
this.head!.previous = node;
node.next = this.head;
this.head = node;
return this.size;
}
public shift() {
if (!this.head) {
return;
}
this.size--;
const node = this.head;
if (this.head === this.tail) {
this.head = null;
this.tail = null;
return node.value;
}
this.head = node.next;
this.head!.previous = null;
return node.value;
}
public pop() {
if (!this.tail) {
return;
}
this.size--;
const node = this.tail;
if (this.head === this.tail) {
this.head = null;
this.tail = null;
return node.value;
}
this.tail = node.previous!;
this.tail.next = null;
return node.value;
}
public peekLeft() {
return this.head?.value;
}
public peekRight() {
return this.tail?.value;
}
*[Symbol.iterator]() {
let current = this.head;
while (current) {
yield current.value;
current = current.next;
}
}
}