Skip to content

Commit

Permalink
Doubly Linked List (#118)
Browse files Browse the repository at this point in the history
* feat: create a Doubly Linked List data structure

* test: fix Liked List test
  • Loading branch information
201flaviosilva committed May 10, 2024
1 parent ef9f855 commit 7846f53
Show file tree
Hide file tree
Showing 6 changed files with 1,043 additions and 35 deletions.
353 changes: 353 additions & 0 deletions src/DataStructures/DoublyLinkedList.js
@@ -0,0 +1,353 @@
/**
* @class DLLNode
* @classdesc Represents a node in a doubly linked list.
*
* @memberof DataStructures
*/
class Node {
/**
* Creates a new Node instance.
* @param {*} value - The value to be stored in the node.
*/
constructor(value) {
if (!value) throw new Error("Node value cannot be undefined.");

this.value = value;
this.next = null;
this.prev = null;
}
}

/**
* Represents a doubly linked list data structure.
*
* @memberof DataStructures
*/
class DoublyLinkedList {
/**
* Creates a new DoublyLinkedList instance.
*
* @example
* new DoublyLinkedList();
* new DoublyLinkedList("Beep");
* new DoublyLinkedList([10,20,30]);
*
* @param {Array|*} value - The value to initialize the list with (optional).
*/
constructor(value) {
this.head = null; // first node to be added
this.tail = null; // last node to be added
this.size = 0;

if (Array.isArray(value)) value.forEach((v) => this.push(v));
else if (value !== undefined) this.push(value);
}

/**
* Prints the values of the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.print(); // 10,20,30
*
* @returns {DoublyLinkedList} The current DoublyLinkedList instance.
*
* @memberof DoublyLinkedList
* @method print
*/
print() {
let temp = this.head;
while (temp !== null) {
console.log(temp.value);
temp = temp.next;
}
return this;
}

/**
* Clears the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.clear();
* dll.toArray(); // []
*
* @returns {DoublyLinkedList} The current DoublyLinkedList instance.
*
* @memberof DoublyLinkedList
* @method clear
*/
clear() {
this.head = null;
this.tail = null;
this.size = 0;
return this;
}

/**
* Retrieves the value at the specified index in the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.get(1); // 20
*
* @param {Number} index - The index of the value to retrieve.
* @param {Boolean} returnNode - Whether to return the Node or the value.
* @returns {Number|Node} The value at the specified index, or the Node if returnNode is true.
*
* @memberof DoublyLinkedList
* @method get
*/
get(index, returnNode = false) {
if (index < 0 || index >= this.size) return undefined;

let temp = this.head;

if (index < this.size / 2) {
for (let i = 0; i < index; i++) {
temp = temp.next;
}
} else {
temp = this.tail;
for (let i = this.size - 1; i > index; i--) {
temp = temp.prev;
}
}

return returnNode ? temp : temp.value;
}

/**
* Sets the value at the specified index in the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.set(1, 0); // 0
*
* @param {Number} index - The index of the value to set.
* @param {Number} value - The new value to set.
* @returns {Boolean} True if the value was set successfully, false otherwise.
*
* @memberof DoublyLinkedList
* @method set
*/
set(index, value) {
const node = this.get(index, true);
if (!node) return false;

node.value = value;
return true;
}

/**
* Adds a new value to the beginning of the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.unshift(0); // 0,10,20,30
*
* @param {Number} value - The value to add.
* @returns {DoublyLinkedList} The current DoublyLinkedList instance.
*
* @memberof DoublyLinkedList
* @method unshift
*/
unshift(value) {
if (!this.head) return this.push(value);

const newNode = new Node(value);

newNode.next = this.head;
this.head.prev = newNode;
this.head = newNode;

this.size++;
return this;
}

/**
* Adds a new value to the end of the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.push(40); // 10,20,30,40
*
* @param {Number} value - The value to add.
* @returns {DoublyLinkedList} The current DoublyLinkedList instance.
*
* @memberof DoublyLinkedList
* @method push
*/
push(value) {
const newNode = new Node(value);

if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
newNode.prev = this.tail;
this.tail = newNode;
}

this.size++;
return this;
}

/**
* Inserts a new value at the specified index in the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.insert(1, 0); // 0,10,20,30
*
* @param {Number} index - The index to insert the value at.
* @param {Number} value - The value to insert.
* @returns {DoublyLinkedList} The current DoublyLinkedList instance.
*
* @memberof DoublyLinkedList
* @method insert
*/
insert(index, value) {
if (index === 0) return this.unshift(value);
else if (index === this.size) return this.push(value);
else if (index < 0 || index > this.size) return false;

const newNode = new Node(value);
const beforeNode = this.get(index - 1, true);

newNode.prev = beforeNode;
newNode.next = beforeNode.next;

beforeNode.next.prev = newNode;
beforeNode.next = newNode;

this.size++;
return this;
}

/**
* Removes the value at the start of the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.shift(); // 20,30
*
* @returns {Number} The value that was removed.
*
* @memberof DoublyLinkedList
* @method shift
*/
shift() {
if (this.size === 0) return;

const temp = this.head;

if (this.size > 1) {
this.head = this.head.next;
this.head.prev = null;
temp.next = null;

this.size--;

} else this.clear();

return temp.value;
}

/**
* Removes the value from the end of the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.pop(); // 10,20
*
* @returns {Number} The value that was removed.
*
* @memberof DoublyLinkedList
* @method pop
*/
pop() {
if (this.size === 0) return;

const temp = this.tail;

if (this.size > 1) {
this.tail = this.tail.prev;
this.tail.next = null;
temp.prev = null;

this.size--;

} else this.clear();

return temp.value;
}

/**
* Removes the value at the given index of the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.remove(1); // 10,30
*
* @param {Number} index - The index of the value to remove.
* @returns {Number} The value that was removed.
*
* @memberof DoublyLinkedList
* @method remove
*/
remove(index) {
if (index < 0 || index >= this.size) return false;
else if (index === 0) return this.shift();
else if (index === this.size - 1) return this.pop();

const node = this.get(index, true);
const prev = node.prev;
const next = node.next;

prev.next = next;
next.prev = prev;

node.prev = null;
node.next = null;

this.size--;
return node.value;
}

// TODO: Implement reverse()
reverse() { }

// TODO: Implement sort()
sort() { }

/**
* Returns an array representation of the linked list.
*
* @example
* const dll = new DoublyLinkedList([10,20,30]);
* dll.toArray(); // [10,20,30]
*
* @returns {Array} The array representation of the linked list.
*
* @memberof DoublyLinkedList
* @method toArray
*/
toArray() {
const arr = [];

let temp = this.head;
while (temp !== null) {
arr.push(temp.value);
temp = temp.next;
}

return arr;
}
}

export {
DoublyLinkedList, Node
};

13 changes: 8 additions & 5 deletions src/DataStructures/LinkedList.js
Expand Up @@ -28,8 +28,8 @@ class LinkedList {
constructor(value) {
if (value !== undefined) {
const newNode = new Node(value);
this.head = newNode;
this.tail = newNode;
this.head = newNode; // first node to be added
this.tail = newNode; // last node to be added
this.size = 1;
} else {
this.head = null;
Expand Down Expand Up @@ -265,7 +265,7 @@ class LinkedList {
* @memberof LinkedList
*/
pop() {
if (!this.size) return undefined;
if (this.size === 0) return undefined;

let pre = this.head;
let temp = this.head;
Expand Down Expand Up @@ -346,6 +346,9 @@ class LinkedList {
return this;
}

// TODO: Implement sort()
sort() { }

/**
* Converts the linked list to an array.
*
Expand Down Expand Up @@ -375,6 +378,6 @@ class LinkedList {
}

export {
Node as LLNode,
LinkedList,
LinkedList, Node
};

0 comments on commit 7846f53

Please sign in to comment.