data-collection.js
Version:
Simple collection classes that can be used in JS/Node.
301 lines (277 loc) • 8.19 kB
JavaScript
const {LinkedNode} = require('../node/LinkedNode');
const {NodedCollection} = require('./NodedCollection');
class LinkedList extends NodedCollection{
/**
* @param root The root element
* */
constructor(root=null){
super(root);
this.size = root?1:0;
}
/**
* Method pushes the given element in the Linked List
* @param new_ele The new element
* @return boolean true, if the push is successful, else false
* */
push(new_ele){
if(!(new_ele instanceof LinkedNode)){
new_ele = new LinkedNode(new_ele);
}
let inserted = false;
if(!this.root){
this.root = new_ele;
inserted = true;
}else{
inserted = this.__insert(new_ele);
}
if(inserted){
this.size++;
}
return inserted;
}
/**
* Method lets you insert an element at the given index
* @param index The index at which the new element is to be inserted
* @param new_ele The new element
* @return boolean true, if the push is successful, else false
* */
insertAt(index, new_ele){
if(!(new_ele instanceof LinkedNode)){
new_ele = new LinkedNode(new_ele);
}
let inserted = false;
if(!this.root){
if(index === 0){
this.root = new_ele;
inserted = true;
}else{
return false;
}
}else if(index === 0){
new_ele.next = this.root;
this.root = new_ele;
inserted = true;
}else{
inserted = this.__insert(new_ele, index);
}
if(inserted){
this.size++;
}
return inserted;
}
/**
* Method gets the element at the given index.
* @param index the index
* @return Object The object at the given index
* */
get(index){
if(index == null){
return undefined;
}
let idx = 0;
let node = null;
this.__traverseAndBreak(n=>{
node = n;
return (idx++ !== index);
});
return ((idx-1)===index && node)?node.data:undefined;
}
/**
* Method checks if the List contains the method passed as the argument
* @param ele The element to be checked
* @return boolean true, if the element is present in the list, else false.
* */
contains(ele){
if(!(ele instanceof LinkedNode)){
ele = new LinkedNode(ele);
}
return (this.indexOf(ele)!==-1);
}
/**
* Method returns the first index of the given element in the list, else returns -1
* @param ele The element whose index in the list is to be checked
* @return int the first index of the element in the list
* */
indexOf(ele){
let index = -1;
if(!(ele instanceof LinkedNode)){
ele = new LinkedNode(ele);
}
this.__traverseAndBreak((node, idx)=>{
if (ele.equals(node)){
index = idx;
}
return (index === -1);
});
return index;
}
/**
* Method returns the last index of the given element in the list, else returns -1
* @param ele The element whose last index in the list is to be checked
* @return int the last index of the element in the list
* */
lastIndexOf(ele){
let index = -1;
if(!(ele instanceof LinkedNode)){
ele = new LinkedNode(ele);
}
this.__traverse((node, idx)=>{
if (ele.equals(node)){
index = idx;
}
return (index === -1);
});
return index;
}
/**
* Method removes the first occurrence of the given element from the list
* @param ele The element which is to be removed from the list
* @return Object The object that is removed, or null
* */
remove(ele){
if(!(ele instanceof LinkedNode)){
ele = new LinkedNode(ele);
}
if(this.root.equals(ele)){
let temp = this.root.data;
this.root = this.root.next;
this.size--;
return temp;
}
let curr = null;
let prev = null;
this.__traverseAndBreak((n, idx)=>{
prev = curr;
curr = n;
return !curr.equals(ele);
});
if(prev !== null && curr !== null && curr.equals(ele)){
let temp = curr.data;
prev.next = curr.next;
this.size--;
return temp;
}
return null;
}
/**
* Method removes the element from the list at the given index
* @param index The index at which the element is to be removed
* @return Object The object that is removed, or null
* */
removeAt(index=0){
return this.__deleteAt(index);
}
/**
* Method removes the element at the end of the list
* @return Object the removed element
* */
pop(){
return this.__deleteAt((this.size-1));
}
/**
* Method removes the element at the start of the list
* @return Object the removed element
* */
shift(){
return this.__deleteAt(0);
}
/**
* Method retrieves, but does not remove, the first element of this list, or returns null if this list is empty
* @return Object first element in the list
* */
peekFirst(){
return this.root.data;
}
/**
* Method retrieves, but does not remove, the last element of this list, or returns null if this list is empty
* (Implemented using Floyd's )
* @return Object last element in the list
* */
peekLast(){
let node = null;
this.__traverse(n => node = n);
return node.data;
}
/**
* Method merges the given array with the list.
* @param array the array to be merged
* */
concat(array = []){
for(let e of array){
if(!(e instanceof LinkedNode)){
e = new LinkedNode(e);
}
this.push(e);
}
}
/**
* Method returns the contents of the list as an array
* @return Array the contents of the list
* */
toArray(){
let arr = [];
this.__traverse(node=>{
arr.push(node.data);
});
return arr;
}
//method traverses through every element in the list with the given consumer
__traverse(consumer, node=this.root){
if(!node){
return;
}
let idx = 0;
while(node){
consumer(node, idx++);
node = node.next;
}
}
//method traverses through every element in the list with the given predicate, and breaks if the predicate return false
__traverseAndBreak(predicate_consumer, node=this.root){
if(!node){
return;
}
let idx = 0;
while(node && predicate_consumer(node, idx++)){
node = node.next;
}
}
//method inserts the given element at the given index
__insert(new_ele, index=this.size){
let idx = 0;
let node = this.root;
while(node && (++idx<index)){
node = node.next;
}
if(idx === index){
new_ele.next = node.next;
node.next = new_ele;
return true;
}
return false;
}
__deleteAt(index){
if(index === 0){
let temp = this.root.data;
this.root = this.root.next;
this.size--;
return temp;
}
let prev_node = null;
let curr_node = null;
let is_equal = true;
this.__traverseAndBreak((node, idx)=>{
prev_node = curr_node;
curr_node = node;
return is_equal = !(index === idx);
});
if(prev_node && curr_node && !is_equal){
let temp = curr_node.data;
prev_node.next = curr_node.next;
this.size--;
return temp;
}
return null;
}
}
module.exports = {LinkedList};