diff --git a/data-structures/doublyLinkedList.js b/data-structures/doublyLinkedList.js new file mode 100644 index 0000000..59cbd19 --- /dev/null +++ b/data-structures/doublyLinkedList.js @@ -0,0 +1,226 @@ +/** + * @author Rashik Ansar + * + * Implementation of doubly linked list + * Doubly linked list is a linear data structure + */ + +class Node { + constructor(data) { + this.data = data; + this.next = null; + this.prev = null; + } +} + +class DoublyLinkedList { + constructor() { + this.head = null; + this.tail = null; + this.length = 0; + } + + /** + * Adding new node as a tail of the linked list + * @param {any} data This dataue is added at the end of list + * @returns {DoublyLinkedList} LinkedList after adding new node as tail + */ + push(data) { + let temp = new Node(data); + if (!this.head) { + this.head = temp; + this.tail = temp; + } else { + this.tail.next = temp; + temp.prev = this.tail; + this.tail = temp; + } + this.length++; + return this; + } + + /** + * Adding new node as a head of the linked list + * @param {any} data This dataue is added at the beginning of the list + * @returns {DoublyLinkedList} LinkedList after adding a new node as head + */ + unshift(data) { + let current = new Node(data); + if (!this.head) { + this.head = current; + this.tail = current; + } else { + this.head.prev = current; + current.next = this.head; + this.head = current; + } + this.length++; + return this; + } + + /** + * Adding a node to the linkedList at specified position + * @param {number} index Position at which new node to insert + * @param {any} data dataue in the new node + * @returns {DoublyLinkedList} LinkedList after inserting a new node + */ + insert(index, data) { + if (index < 0 || index > this.length) { + throw Error('Given index is out of range'); + } + if (index === this.length) { + return this.push(data); + } + if (index === 0) { + return this.unshift(data); + } + let insertNode = new Node(data); + let previous = this.get(index - 1); + let temp = previous.next; + previous.next = insertNode; + insertNode.prev = previous; + insertNode.next = temp; + temp.prev = insertNode; + this.length++; + return this; + } + + /** + * Removes the node at the end of linked list(tail of linked list) + * @returns {Node} the node which is going to pop + */ + pop() { + if (!this.head) { + throw Error( + 'UNDERFLOW :::: LinkedList is empty, there is nothing to remove' + ); + } + let temp = this.tail; + if (this.length === 1) { + this.head = null; + this.tail = null; + } else { + this.tail = temp.prev; + this.tail.next = null; + temp.prev = null; + } + this.length--; + return temp; + } + + /** + * Removes the node from the beginnig of linked list(head of linked list) + * @returns {Node} the node which is going to shift + */ + shift() { + if (!this.head) { + throw Error( + 'UNDERFLOW :::: LinkedList is empty, there is nothing to remove' + ); + } + let current = this.head; + if (this.length === 1) { + this.head = null; + this.tail = null; + } else { + this.head = current.next; + this.head.prev = null; + current.next = null; + } + this.length--; + return current; + } + + /** + * Removes a node from the linkedList at specified position + * @param {number} index + * @returns {Node} Node which is removed from LinkedList + */ + remove(index) { + if (index < 0 || index > this.length) { + throw Error('Given index is out of range'); + } + if (index === this.length - 1) { + return this.pop(); + } + if (index === 0) { + return this.shift(); + } + let removeNode = this.get(index); + let before = removeNode.prev; + let after = removeNode.next; + before.next = after; + after.prev = before; + removeNode.next = null; + removeNode.prev = null; + this.length--; + return removeNode; + } + + /** + * Retrieve the node at specified index + * @param {number} index Index of the node + * @returns {Node} LinkedList Node at specified index + */ + get(index) { + if (index < 0 || index >= this.length) { + throw Error('Given index is out of range'); + } + let current; + if (index <= this.length / 2) { + let counter = 0; + current = this.head; + while (counter !== index) { + current = current.next; + counter++; + } + } else { + let counter = this.length - 1; + current = this.tail; + while (counter !== index) { + current = current.prev; + counter--; + } + } + return current; + } + + /** + * Change the data of node at specified index + * @param {number} index Index of the node + * @param {any} data data replaces the current data at given index + * @returns {DoublyLinkedList} LinkedList + */ + set(index, data) { + let existedNode = this.get(index); + if (existedNode) { + existedNode.data = data; + return this; + } + } + + /** + * Traversing or Printing the Linked list + */ + traverse() { + let current = this.head; + console.log(this.length); + while (current) { + console.log(current.data); + current = current.next; + } + } + + /** + * @returns {[]} Linkedlist data as elements in Array + */ + listAsArray() { + let arr = []; + let current = this.head; + while (current) { + arr.push(current.data); + current = current.next; + } + return arr; + } +} diff --git a/data-structures/hashTable.js b/data-structures/hashTable.js new file mode 100644 index 0000000..603c9d2 --- /dev/null +++ b/data-structures/hashTable.js @@ -0,0 +1,76 @@ +/** + * @author Rashik Ansar + * + * Implementation of Hash Table + */ + +class HashTable { + constructor(size = 47) { + this.keyMap = new Array(size); + } + + /** + * Hash Function + * Private method to generate hash of the given data + * @param {*} key data to hash + */ + _hash(key) { + let total = 0; + const RANDOM_PRIME = 31; + for (let i = 0; i < Math.min(key.length, 100); i++) { + let char = key[i]; + let value = char.charCodeAt(0) - 96; + total = (total * RANDOM_PRIME + value) % this.keyMap.length; + } + return total; + } + + set(key, value) { + let index = this._hash(key); + if (!this.keyMap[index]) { + this.keyMap[index] = []; + } + this.keyMap[index].push([key, value]); + return this; + } + + get(key) { + let index = this._hash(key); + if (this.keyMap[index]) { + for (let i = 0; i < this.keyMap[index].length; i++) { + if (this.keyMap[index][i][0] === key) { + return this.keyMap[index][i]; + } + } + } + return undefined; + } + + values() { + let valArray = []; + for (let i = 0; i < this.keyMap.length; i++) { + if (this.keyMap[i]) { + for (let j = 0; j < this.keyMap[i].length; j++) { + if (!valArray.includes(this.keyMap[i][j][1])) { + valArray.push(this.keyMap[i][j][1]); + } + } + } + } + return valArray; + } + + keys() { + let keysArray = []; + for (let i = 0; i < this.keyMap.length; i++) { + if (this.keyMap[i]) { + for (let j = 0; j < this.keyMap[i].length; j++) { + if (!keysArray.includes(this.keyMap[i][j][0])) { + keysArray.push(this.keyMap[i][j][0]); + } + } + } + } + return keysArray; + } +} diff --git a/data-structures/priorityQueue.js b/data-structures/priorityQueue.js new file mode 100644 index 0000000..1eb68ca --- /dev/null +++ b/data-structures/priorityQueue.js @@ -0,0 +1,117 @@ +/** + * @author Rashik Ansar + * + * Implemntaion of priority queue + * Lower the priority value higher its priority + * under the hood its implementing minBinaryHeap + */ +class PriorityQueue { + constructor() { + this.values = []; + } + + /** + * Adding data to the queue + * @param {*} data Data to add into queue + * @param {*} priority Priority of the data + * @returns {PriorityQueue} + */ + enqueue(data, priority) { + let temp = new Node(data, priority); + this.values.push(temp); + this.bubbleUp(); + return this; + } + + /** + * removing a node from the queue + * @returns {Node} + */ + dequeue() { + const min = this.values[0]; + const end = this.values.pop(); + if (this.values.length > 0) { + this.values[0] = end; + this.sinkDown(); + } + return min; + } + + /** + * enqueue helper function + */ + bubbleUp() { + let index = this.values.length - 1; + const element = this.values[index]; + while (index > 0) { + let parentIndex = Math.floor((index - 1) / 2); + let parent = this.values[parentIndex]; + // if (element.priority <= parent.priority) break; //maxBinaryHeap condition + if (element.priority >= parent.priority) break; //minBinaryHeap condition + this.values[parentIndex] = element; + this.values[index] = parent; + index = parentIndex; + } + } + + /** + * dequeue helper function + */ + sinkDown() { + let index = 0; + const length = this.values.length; + const element = this.values[index]; + while (true) { + let leftChildIndex = 2 * index + 1; + let rightChildIndex = 2 * index + 2; + let leftChild; + let rightChild; + let swap = null; + + if (leftChildIndex < length) { + leftChild = this.values[leftChildIndex]; + // Change below comparision operators to make maxBinaryHeap + if (leftChild.priority < element.priority) { + swap = leftChildIndex; + } + } + + if (rightChildIndex < length) { + rightChild = this.values[rightChildIndex]; + // Change below comparision operators to make maxBinaryHeap + if ( + (!swap && rightChild.priority < element.priority) || + (swap && rightChild.priority < leftChild.priority) + ) { + swap = rightChildIndex; + } + } + + if (!swap) break; + + this.values[index] = this.values[swap]; + this.values[swap] = element; + index = swap; + } + } +} + +class Node { + constructor(data, priority) { + this.data = data; + this.priority = priority; + } +} + +let a = new PriorityQueue(); +a.enqueue('Common Cold', 10); +a.enqueue('Gunshot wound', 2); +a.enqueue('Fever', 8); + +console.log(a); +a.dequeue(); +console.log(a); +a.dequeue(); +console.log(a); +a.dequeue(); +console.log(a); diff --git a/data-structures/queue.js b/data-structures/queue.js new file mode 100644 index 0000000..098ad47 --- /dev/null +++ b/data-structures/queue.js @@ -0,0 +1,68 @@ +/** + * @author Rashik Ansar + * + * Implementation of Queue Data structure + * Queue follows FIFO (First In First Out) Principle + */ + +class Node { + constructor(data) { + this.data = data; + this.next = null; + } +} + +class Queue { + constructor() { + this.first = null; + this.last = null; + this.size = 0; + } + + /** + * Adding data to the end of queue + * @param {*} data Data to add in the queue + * @returns {Queue} Returns the queue after adding new data + */ + enqueue(data) { + let newNode = new Node(data); + if (!this.first) { + this.first = newNode; + this.last = newNode; + } else { + this.last.next = newNode; + this.last = newNode; + } + this.size++; + return this; + } + + /** + * Removing data from the beginning of the queue + * @returns Data that is removing from queue + */ + dequeue() { + if (!this.first) { + throw Error( + 'UNDERFLOW::: The queue is empty, there is nothing to remove' + ); + } + let temp = this.first; + if (this.first === this.last) { + this.last = null; + } + this.first = this.first.next; + this.size--; + return temp.data; + } + + /** + * @returns First element in the queue + */ + peek() { + if (!this.first) { + throw Error('Stack is empty'); + } + return this.first.data; + } +} diff --git a/data-structures/singlyLinkedList.js b/data-structures/singlyLinkedList.js new file mode 100644 index 0000000..72b091e --- /dev/null +++ b/data-structures/singlyLinkedList.js @@ -0,0 +1,233 @@ +/** + * @author Rashik Ansar + * + * Implementation of singly linked list + * Singly linked list is a linear data strucutre + */ + +class Node { + constructor(data) { + this.data = data; + this.next = null; + } +} + +class SinglyLinkedList { + constructor() { + this.head = null; + this.tail = null; + this.length = 0; + } + + /** + * Adding new node as a tail of the linked list + * @param {any} data This dataue is added at the end of list + * @returns {SinglyLinkedList} LinkedList after adding new node as tail + */ + push(data) { + let temp = new Node(data); + if (!this.head) { + this.head = temp; + this.tail = this.head; // temp + } else { + this.tail.next = temp; + this.tail = temp; + } + this.length++; + return this; + } + + /** + * Adding new node as a head of the linked list + * @param {any} data This dataue is added at the beginning of the list + * @returns {SinglyLinkedList} LinkedList after adding a new node as head + */ + unshift(data) { + let temp = new Node(data); + if (!this.head) { + this.head = temp; + this.tail = this.head; + } else { + temp.next = this.head; + this.head = temp; + } + this.length++; + return this; + } + + /** + * Adding a node to the linkedList at specified position + * @param {number} index Position at which new node to insert + * @param {any} data dataue in the new node + * @returns {SinglyLinkedList} LinkedList after inserting a new node + */ + insert(index, data) { + if (index < 0 || index > this.length) { + throw Error('Given index is out of range'); + } + if (index === this.length) { + return this.push(data); + } + if (index === 0) { + return this.unshift(data); + } + let insertNode = new Node(data); + let previous = this.get(index - 1); + let temp = previous.next; + previous.next = insertNode; + insertNode.next = temp; + this.length++; + return this; + } + + /** + * Removes the node at the end of linked list(tail of linked list) + * @returns {Node} the node which is going to pop + */ + pop() { + if (!this.head) { + throw Error( + 'UNDERFLOW :::: LinkedList is empty, there is nothing to remove' + ); + } + let current = this.head; + let temp = current; + while (current.next) { + temp = current; + current = current.next; + } + this.tail = temp; + this.tail.next = null; + this.length--; + this.emptyListCheck(); + return current; + } + + /** + * Removes the node from the beginnig of linked list(head of linked list) + * @returns {Node} the node which is going to shift + */ + shift() { + if (!this.head) { + throw Error( + 'UNDERFLOW :::: LinkedList is empty, there is nothing to remove' + ); + } + let current = this.head; + this.head = current.next; + this.length--; + this.emptyListCheck(); + return current; + } + + /** + * Removes a node from the linkedList at specified position + * @param {number} index + * @returns {Node} Node which is removed from LinkedList + */ + remove(index) { + if (index < 0 || index > this.length) { + throw Error('Given index is out of range'); + } + if (index === this.length - 1) { + return this.pop(); + } + if (index === 0) { + return this.shift(); + } + let previous = this.get(index - 1); + let temp = previous.next; + previous.next = temp.next; + this.length--; + return temp; + } + + /** + * Retrieve the node at specified index + * @param {number} index Index of the node + * @returns {Node} LinkedList Node at specified index + */ + get(index) { + if (index < 0 || index >= this.length) { + throw Error('Given index is out of range'); + } + let counter = 0; + let current = this.head; + while (counter !== index) { + current = current.next; + counter++; + } + return current; + } + + /** + * Change the data of node at specified index + * @param {number} index Index of the node + * @param {any} data data replaces the current data at given index + * @returns {SinglyLinkedList} LinkedList + */ + set(index, data) { + // Here error checking will be done by the get method itself + // No need to specify explicitly + let existedNode = this.get(index); + if (existedNode) { + existedNode.data = data; + return this; + } + } + + /** + * Reversing the Linked list + * @returns {SinglyLinkedList} LinkedList + */ + reverse() { + let temp = this.head; + this.head = this.tail; + this.tail = temp; + + let previous = null; + let after = null; + while (temp) { + after = temp.next; + temp.next = previous; + previous = temp; + temp = after; + } + return this; + } + + /** + * Traversing or Printing the Linked list + */ + traverse() { + let current = this.head; + while (current) { + console.log(current.data); + current = current.next; + } + } + + /** + * @returns {[]} Linkedlist data as elements in Array + */ + listAsArray() { + let arr = []; + let current = this.head; + while (current) { + arr.push(current.data); + current = current.next; + } + return arr; + } + + /** + * Utility Function (PRIVATE FUNCTION) + * if the length is zero then assign null to both head and tail + */ + emptyListCheck() { + if (this.length === 0) { + this.head = null; + this.tail = null; + } + } +} diff --git a/graphs/unweightedGraph.js b/graphs/unweightedGraph.js new file mode 100644 index 0000000..7d48e5a --- /dev/null +++ b/graphs/unweightedGraph.js @@ -0,0 +1,154 @@ +/** + * @author Rashik Ansar + * Implemtaion of graph with the help of Adjacency List + * Its Unweighted graph implemetation + */ + +class Graph { + constructor() { + this.adjacencyList = {}; + } + + /** + * Adding a vertex to the graph + * @param {*} vertex The data of the vertex to add into graph + * @returns {Graph} + */ + addVertex(vertex) { + if (this.adjacencyList[vertex]) { + throw Error(`${vertex} already exist in graph... `); + } else { + this.adjacencyList[vertex] = []; + } + // return this; + } + + /** + * Removing a vertex from the graph + * @param {*} vertex The data of the vertex to remove from graph + */ + removeVertex(vertex) { + if (this.adjacencyList[vertex]) { + while (this.adjacencyList[vertex].length) { + const itemInArray = this.adjacencyList[vertex].pop(); + this.removeEdge(vertex, itemInArray); + } + delete this.adjacencyList[vertex]; + // return this; // Added for testing before traversal methods + } else { + throw Error(`${vertex} doesn't exist...`); + } + } + + /** + * Adding an edge between two vertices in the graph + * @param {*} vertex1 + * @param {*} vertex2 + */ + addEdge(vertex1, vertex2) { + if (this.adjacencyList[vertex1] && this.adjacencyList[vertex2]) { + this.adjacencyList[vertex1].push(vertex2); + this.adjacencyList[vertex2].push(vertex1); + // return this; + } else { + throw Error('Given vertex/vertices might not exist in graph...'); + } + } + + /** + * Removing an existing edge between two vertices in the graph + * @param {*} vertex1 + * @param {*} vertex2 + */ + removeEdge(vertex1, vertex2) { + if (this.adjacencyList[vertex1] && this.adjacencyList[vertex2]) { + this.adjacencyList[vertex1] = this.adjacencyList[vertex1].filter( + i => i !== vertex2 + ); + this.adjacencyList[vertex2] = this.adjacencyList[vertex2].filter( + i => i !== vertex1 + ); + // return this; + } else { + throw Error('Given vertex/vertices might not exist in graph...'); + } + } + + /** + * Travesal of the graph by breadth-first approach + * @param {*} start Starting vertex for traversal + * @returns {[]} + */ + breadthFirstTraversal(start) { + const queue = []; + const result = []; + const visited = {}; + let current; + queue.push(start); + visited[start] = true; + + while (queue.length) { + current = queue.shift(); + result.push(current); + this.adjacencyList[current].forEach(x => { + if (!visited[x]) { + visited[x] = true; + queue.push(x); + } + }); + } + return result; + } + + /** + * Depth First Traversal (recursive approach) + * + * @param {*} start Starting vertex for traversal + * @returns {[]} + */ + DFTrecursuive(start) { + const visited = {}; + const result = []; + const adjacencyList = this.adjacencyList; + function dfs(vertex) { + if (!vertex) { + throw Error('Incorrect starting vertex!'); + } + visited[vertex] = true; + result.push(vertex); + adjacencyList[vertex].forEach(x => { + if (!visited[x]) { + return dfs(x); + } + }); + } + dfs(start); + return result; + } + /** + * Depth First Traversal (Iterative approach) + * + * @param {*} start Starting vertex for traversal + * @returns {[]} + */ + DFTiterative(start) { + const stack = []; + const visited = {}; + const result = []; + let current; + + stack.push(start); + visited[start] = true; + while (stack.length) { + current = stack.pop(); + result.push(current); + this.adjacencyList[current].forEach(x => { + if (!visited[x]) { + visited[x] = true; + stack.push(x); + } + }); + } + return result; + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy