Linked list of JavaScript data structure

Time:2020-11-24

Linked list data structure

To store multiple elements, arrays may be the most commonly used data structure in JS, but inserting or removing items from the beginning or middle of an array is costly because elements need to be moved.
A linked list stores an ordered set of elements, but different from an array. The elements in a linked list are not placed continuously in memory. Instead, each element is composed of a node storing the element itself and a reference to the next element. This is a normal linked list. A bidirectional linked list has an element reference pointing to the previous one. A circular linked list can be a one-way reference or a one-way reference The last element of the circular list points to the next element, not undefined, but the first element head
Linked list of JavaScript data structure
The drawing is a bit of a scum. This is a two-way circular list.
Create a simple linked list

function defaultEquals(a,b){
    return a===b;
}
class Node{
    constructor(el){
        this.el = el;
        this.next = undefined;
    }
}
Class LinkedList {// one way linked list
    constructor(equals = defaultEquals){
        this.count = 0;
        this.head = undefined;
        this.equalsFn = equals;
    }
    push(el){
        const tail = this.getElAt(this.count-1);
        if(tail.next){
            Throw 'circular linked list does not support this method! ';
            return;
        }
        const node = new Node(el);
        let current;
        if(!this.head){
            this.head = node;
        }else{
            current = this.head;
            while(current.next){
               current = current.next;
            }
            current.next = node;
        }
        this.count++;
    }
    Getelat (index) {// get elements according to location
         if(index>=0 && index<this.count){
            let current = this.head;
            for(let i=0;i<index && current;i++){
                current = current.next;
            }
            return current;
         }
         return undefined;
    }
    Removeat (index) {// remove according to location
        if(index>=0 && index<this.count){
            let current = this.head;
            if(index===0){
                this.head = current.next;
            }else{
                let previous= this.getElAt (index-1); // get the previous one
                current = previous.next;         
                previous.next = current.next;
            }
            this.count--;
            return current.el;
        }
        return undefined;
    }
    Insert (EL, index) {// insert anywhere
        if(index>=0 && index<=this.count){
            const node = new Node(el);
            if(index===0){
                const current = this.head;
                node.next = current;
                this.head = node;
            }else{
                const previous = this.getElAt(index-1);
                const current = previous.next;
                node.next = current;
                previous.next = node;
            }
            this.count++;
            return true;
        }
        return false;
    }
    indexOf(el){
        let current = this.head;
        for(let i=0;i<this.count;i++){
            if(this.equalsFn(current.el,el)){
                return i;
            }
            current = current.next;
        }
        return -1;
    }
    remove(el){
        let index = this.indexOf(el);
        return this.removeAt(index);
    }
    size(){
        return this.count;
    }
    isEmpty(){
        return this.size() === 0;
    }
    getHead(){
        return this.head;
    }
    toString(){
        if(!this.head){
            return '';
        }
        let str = `${this.head.el}`;
        let current = this.head.next;
        for(let i=0;i<this.size() && current;i++){
            str=`${str}${current.el}`;
            current = current.next;
        }
        return str;
    }
}

Double linked list, adding a reference to the previous element

class DoublyNode extends Node{
    constructor(el,next,prev){
        super(el);
        this.prev = prev;
    }
}
class DoublyLinkedList extends LinkedList{
    constructor(equals = defaultEquals){
       super(equals);
       this.tail = undefined;
    }
     push(el){
        const node = new DoublyNode(el);
        let current;
        if(!this.head){
            this.head = node;
            
        }else{
            current = this.head;
            while(current.next){
               current = current.next;
            }
            current.next = node;
            node.prev = current;
        }
        this.tail = node;
        this.count++;
    }
    insert(el,index){
        if(index>=0 && index<=this.count){
            const node = new DoublyNode(el);
            let current = this.head;
            if(index===0){
                if(!this.head){
                    this.head = node;
                    this.tail = node;
                }else{
                    node.next = current;
                    current.prev = node;
                    this.head = node;
                }
            }else if(index === this.count){
                current = this.tail;
                node.prev = current;
                current.next = node;
                this.tail = node;
            }else{
                const previous = this.getElAt(index-1);
                current = previous.next;
                previous.next = node;
                node.prev = previous;
                node.next = current;
                current.prev = node;
            }
            this.count++;
            return true;
        }
        return false;
    }
    removeAt(index){
        if(index>=0 && index<this.count){
            let current = this.head;
            if(index===0){
                this.head = current.next;
                if(this.count===1){
                    this.tail=undefined;
                }else{
                    this.head.prev = undefined;
                }
            }else if(index===this.count-1){
                current = this.tail;
                this.tail = current.prev;
                this.tail.next = undefined;
            }else{
                current = this.getElAt(index);
                const previous = current.prev;
                previous.next = current.next;
                current.next.prev = previous;
            }
            this.count--;
            return curren.el;
        }
        return undefined;
    }
}

Loop linked list, one-way, the last element points to the next element pointer tail.next It’s not undefined, but the first element, head, which is a reference on the first element head.prev Not undefined, but tail

class CircularLinkedList extends LinkedList{
    constructor(equalsFn=defaultEquals){
        super(equalsFn)
    }
   
    insert(el,index){
        if(index>=0 && index<=this.count){
            const node = new Node(el);
            const current = this.head;
            if(index==0){
                if(!this.head){
                    this.head = node;
                    node.next = this.head;
                }else{
                    node.next = current;
                    current = this.getElAt(this.size()-1);
                    this.head = node;
                    current.next = this.head;
                }
            } else {
                const previous = this.getElAt(index-1);
                node.next = previous.next;
                previous.next = node;
            }
            this.count++;
            return true;
        }
        return false;
    }
    removeAt(index){
        if(index>=0 && index<this.count){
            let current = this.head;
            if(index===0){
                if(this.size()==1){
                    this.head = undefined;
                }else{
                    const removed = this.head;
                    current = this.getElAt(this.size()-1);
                    this.head = this.head.next;
                    current.next = this.head;
                    current = removed;
                }
            }else{
                const previous = this.getElAt(index-1);
                current = previous.next;
                previous.next = current.next;
            }
            this.count--;
            return current.el;
        }
        return undefined;
    }
}

Ordered list, according to their own rules to generate a comparison function, to insert elements into the correct position to ensure the order of the list.

const Compare = {
    LESS_THAN:-1,
    BIGGER_THAN:1
}
function defultCompare(a,b){
    if(a===b){
        return 0;
    }
    return a<b?Compare.LESS_THAN:Compare.BIGGER_THAN;
}
class SortedLinkedList extends LinkedList{
    constructor(equalsFn=defaultEquals,compareFn=defultCompare) {
        super(equalsFn)
        this.compareFn = compareFn;
    }
    insert(el){
        if(this.isEmpty()){
            return super.insert(el,0);
        }else{
            const pop = this.getIndexNextSortedEl(el);
            return super.insert(el,pop);
        }
    }
    getIndexNextSortedEl(el){
        let current = this.head;
        let i = 0;
        for(;i<this.size() && current;i++){
            const comp = this.compareFn(el,current.el);
            if(comp === Compare.LESS_THAN){
                return i;
            }
            current = current.next;
        }
        return i;
    }
}

The push method can’t be used in the ordered list, otherwise the order can’t be guaranteed.
You can use linked lists to create other data structures, such as stacks, queues, and bidirectional queues.
The most important advantage of linked list relative to array is that it can easily add or delete elements without moving the elements in the list. Therefore, when many elements need to be added and deleted frequently, the best choice is linked list rather than array.
This content learns and learns JavaScript data structure and algorithm