Singly & Doubly Linked Lists - Stacks and Queues

Who it looks like: https://visualgo.net/en/list

[!info] Sorting Algorithms Animations
These pages show 8 different sorting algorithms on 4 different initial conditions.
https://www.toptal.com/developers/sorting-algorithms

In the end, you can understand the following image

// Singly linked list:
class Node{
    constructor(val){
        this.val = val;
        this.next = null;
    }
}

class SinglyLinkedList{
    constructor() {
        this.head = null
        this.tail = null
        this.length = 0
    }
    push(val) {
        const newNode = new Node(val)
        // { head: null, tail: null, length: 0 }
        if(!this.head) {
            this.head = newNode
            this.tail = this.head
            /*
            {
                head: Node { val: 'hello', next: null },
                tail: Node { val: 'hello', next: null },
                length: 1
            }
            */
        } else {
            this.tail.next = newNode
            this.tail = newNode
            /*
            {
                head: Node {
                    val: 'hello',
                    next: Node {
                        val: 'goodby',
                        next: null
                    }
                },
                tail: Node { val: 'goodby', next: null },
                length: 2
            }
            */
        }
        // (hello) -> (goodmay)
        this.length++
        return this
    }
    pop(){
        if(!this.head) return undefined
        let current = this.head
        let newTail = current
        while(current.next) {
            newTail = current
            current = current.next
        }
        this.tail = newTail
        this.tail.next = null
        this.length--
        if(this.length === 0) {
            this.head = null
            this.tail = null
        }
        return current
    }
    shift(){
        if(!this.head) return undefined
        let current = this.head
        this.head = current.next
        this.length--
        if(this.length === 0) {
            this.tail = null
        }
        return current
    }
    unshift(val){
        const newNode = new Node(val)
        if(!this.head) {
            this.head = newNode
            this.tail = this.head
        } else {
            newNode.next = this.head
            this.head = newNode
        }
        this.length++
        return this
    }
    get(index) {
        if(index < 0 || index >= this.length) return null
        let counter = 0
        let current = this.head
        while(counter !== index) {
            current = current.next
            counter++
        }
        return current
    }
    set(index, value) {
        const foundNode = this.get(index)
        if(foundNode) {
            foundNode.val = value
            return true
        }
    }
    insertInto(index, value) {
        if(index < 0 || index > this.length) return false
        if(index === this.length) {
            this.push(value)
            return true
        }
        if(index === 0) {
            this.unshift(val)
            return true
        }
        const newNode = new Node(value)
        const foundNodeHead = this.get(index - 1)
        const temp = foundNodeHead.next
        foundNodeHead.next = newNode
        newNode.next = temp
        this.length++
        return true
    }
    remove(index) {
        if(index < 0 || index >= this.length) return false
        if(index === this.length - 1) {
            this.pop()
            return true
        }
        if(index === 0) {
            this.unshift(val)
            return true
        }
        const previousNode = this.get(index - 1)
        const removed = previousNode.next
        previousNode.next = removed.next
        this.length--
        return true
    }
    reverse() {
        let node = this.head
        this.head = this.tail
        this.tail = node
        let next
        let prev = null
        for(let i = 0; i < this.length; i++) {
            next = node.next
            node.next = prev
            prev = node
            node = next
        }
        return this
    }
}
const list = new SinglyLinkedList()
list.push('hello')
list.push('jo')
list.push('goodby')
list.reverse()
console.log(list)

Doubly-linked-list

// I recommend to use Snippets from chrome
class Node {
    constructor(val) {
        this.val = val
        this.next = null
        this.prev = null
    }
}
class DoublyLinkedList {
    constructor() {
        this.head = null
        this.tail = null
        this.length = 0
    }
    push(val) {
        const newNode = new Node(val)
        // { head: null, tail: null, length: 0 }
        if (!this.length) {
            this.head = newNode
            this.tail = newNode
        } else {
            this.tail.next = newNode
            newNode.prev = this.tail
            this.tail = newNode
        }
        this.length++
        return this
    }
    pop() {
        if (!this.head) return undefined
        const poppedNode = this.tail
        if (this.length === 1) {
            this.head = null
            this.tail = null
        } else {
            this.tail = poppedNode.prev
            this.tail.next = null
            poppedNode.prev = null
        }
        this.length--
        return poppedNode
    }

    shift() {
        if (!this.head) return undefined
        let current = this.head
        if (this.length === 1) {
            this.head = null
            this.tail = null
        } else {
            this.head = current.next
            this.head.prev = null
            current.next = null
        }
        this.length--
        return current
    }
    unshift(val) {
        const newNode = new Node(val)
        if (!this.head) {
            this.head = newNode
            this.tail = this.head
        } else {
            this.head.prev = newNode
            newNode.next = this.head
            this.head = newNode
        }
        this.length++
        return this
    }

    get(index) {
        if (index < 0 || index >= this.length) return null
        let count, current
        if (index <= this.length / 2) {
            count = 0
            current = this.head
            while (count !== index) {
                current = current.next
                count++
            }
        } else {
            count = this.length - 1
            current = this.tail
            while (count !== index) {
                current = current.prev
                count--
            }
        }
        return current
    }
    set(index, val) {
        let current = this.get(index)
        if (current !== null) {
            current.val = val
            return true
        }
        return false
    }
    insert(index, val) {
        if (index < 0 || index > this.length) return false
        if (index === 0) return this.unshift(val)
        let newNode = new Node(val)
        let beforeNode = this.get(index - 1)
        let afterNode = beforeNode.next
        beforeNode.next = newNode
        newNode.prev = beforeNode
        newNode.next = afterNode
        afterNode.prev = newNode
        this.length++
        return true
    }
    remove(index) {
        if (index < 0 || index > this.length) return false
        if (index === 0) return this.shift(val)
        if (index + 1 === this.length) return this.pop()
        let removeNode = this.get(index)
        removeNode.prev.next = removeNode.next
        removeNode.next.prev = removeNode.prev
        removeNode.next = null
        removeNode.prev = null
        this.length--
        return removeNode
    }
}
const list = new DoublyLinkedList()
list.push('hello')
list.push('world')
list.insert(1, 'joao')
list.remove(2)
console.log(list)