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
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