I've been studying data structures and have taken a stab at implementing a doubly LL in JavaScript. Please review and advise on any additional improvements and optimizations. I'm more interested in feedback particularly regarding the implementations of removeAt()
, contains()
and getItem()
methods as they share similar, repetitive code:
//Blueprints
function Node(val){
this.data = val;
this.next = null;
this.prev = null;
}
function DoublyList(){
this._length = 0;
this._isCircular = false;
this.head = null;
this.tail = null;
}
//Adds to the list
DoublyList.prototype.add = function(val){
var node = new Node(val);
if(this._length){
this.tail.next = node;
node.prev = this.tail;
this.tail = node;
}else{
this.head = node;
this.tail = node;
}
this._length++;
return node;
}
//Check if list is empty
DoublyList.prototype.isEmpty = function(){
return this._length===0;
}
//Contains method returns index if true
DoublyList.prototype.contains = function(val){
if(this.isEmpty()){
return 'List is Empty';
}
var currentNode = this.head, i=0;
//if val is in 1st node
if(currentNode.data === val){
return 0;
}
//if val is in last node
if(this.tail.data === val){
return (this._length-1);
}
//if val is in middle
while(i++ < (this._length-1)){
if(currentNode.data === val){
return (i-1);
}
currentNode = currentNode.next;
}
return false;
}
//Make circular
DoublyList.prototype.makeCircular = function(){
if(!this.isEmpty()){
this.head.prev = this.tail;
this.tail.next = this.head;
this._isCircular = true;
}
}
//get data by node index
DoublyList.prototype.getItem = function(index){
if(this.isEmpty()){
return 'List is Empty';
}
if(index<0 || index > this._length){
return 'Invalid Index!';
}
var currentNode = this.head, i=0;
//if first item in list
if(index===0){
return currentNode.data;
}
//if last item in list
if(index === (this._length-1)){
return this.tail.data;
}
//if item is in middle of list
while(i++ < index){
currentNode = currentNode.next;
}
return currentNode.data;
}
DoublyList.prototype.removeAt = function(index){
if(this.isEmpty()){
return 'List is Empty';
}
if(index<0 || index > this._length){
return 'Invalid Index!';
}
var currentNode = this.head, i=0;
//if first item in list: O(1)
if(index===0){
this.head = currentNode.next;
this.head.prev = this.tail;
this.tail.next = this.head;
this._length--;
return this;
}
//if last item in list: O(1)
if(index === (this._length-1)){
this.tail = this.tail.prev;
this.tail.next = this.head;
this.head.prev = this.tail;
this._length--;
return this;
}
//if item is in middle of list: O(n)
while(i++ < index){
currentNode = currentNode.next;
}
var temp = currentNode;
temp.prev.next = currentNode.next;
this._length--;
return this;
}
var doublyList = new DoublyList();
console.log('isEmpty:\n'+doublyList.isEmpty());
doublyList.add(5);
doublyList.add(10);
doublyList.add(15);
doublyList.add(20);
doublyList.add(25);
doublyList.add(30);
doublyList.add(35);
doublyList.add(40);
console.log('Added items...\n');
console.log('Original List:\n'+doublyList);
console.log('makeCircular:\n'+doublyList.makeCircular());
console.log('Circular List:\n'+doublyList);
console.log('Get 3rd item:\n'+doublyList.getItem(2));
console.log('Contains:\n'+doublyList.contains(15));
console.log('RemoveAt:\n'+doublyList.removeAt(2));