├── README.md ├── algorithms ├── graphs │ ├── BFS.mjs │ ├── Backtrack.mjs │ └── DFS.mjs ├── search │ └── BinarySearch.mjs └── sorting │ ├── HeapSort.mjs │ ├── MergeSort.mjs │ └── QuickSort.mjs ├── data-structures └── Graph.mjs ├── graphs JAVA ├── ArticulationPoint.java ├── BFS.java ├── BiPartite.java ├── DFS.java ├── DFSCycleDetection.java ├── Graph.java ├── GraphTraversal.java ├── ShortestDistance.java ├── StrongComponents.java └── TopologicalSort.java ├── implementations ├── backtracking │ ├── allPaths.mjs │ ├── derangements.mjs │ ├── multisetPermutation.mjs │ ├── permutation.mjs │ ├── subset.mjs │ └── sudoku.mjs ├── dynamic-programming │ ├── binomial-coefficient.mjs │ ├── edit-distance.mjs │ └── fibonacci.mjs ├── graphs │ ├── Dijkstra.mjs │ ├── Kruskal.mjs │ ├── Prims.mjs │ ├── articulationPoint.mjs │ ├── graphTraversal.mjs │ └── topologicalSort.mjs ├── search │ └── binarySearchWithBoundaries.mjs └── sort │ └── sort.mjs ├── node_modules └── @datastructures-js │ ├── heap │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── index.d.ts │ ├── index.js │ ├── package.json │ └── src │ │ ├── customHeap.d.ts │ │ ├── customHeap.js │ │ ├── heap.d.ts │ │ ├── heap.js │ │ ├── maxHeap.d.ts │ │ ├── maxHeap.js │ │ ├── minHeap.d.ts │ │ └── minHeap.js │ └── priority-queue │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── index.d.ts │ ├── index.js │ ├── package.json │ └── src │ ├── maxPriorityQueue.d.ts │ ├── maxPriorityQueue.js │ ├── minPriorityQueue.d.ts │ ├── minPriorityQueue.js │ ├── priorityQueue.d.ts │ └── priorityQueue.js └── package-lock.json /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Data Structures & Algorithms in JavaScript

3 | Solutions to wide range of programs on Data Structures and Algorithms in JavaScript 4 |
5 | -------------------------------------------------------------------------------- /algorithms/graphs/BFS.mjs: -------------------------------------------------------------------------------- 1 | export default class BreadthFirstSearch { 2 | constructor(graph) { 3 | this.graph = graph; 4 | this.parents = new Array(graph.vertices + 1); 5 | this.discovered = new Array(graph.vertices + 1); 6 | this.processed = new Array(graph.vertices + 1); 7 | } 8 | 9 | search(root) { 10 | const queue = []; 11 | 12 | queue.push(root); 13 | this.discovered[root] = true; 14 | this.parents[root] = -1; 15 | 16 | while (queue.length) { 17 | let v = queue.shift(); 18 | 19 | this.processVertexEarly?.(v); 20 | this.processed[v] = true; 21 | 22 | let node = this.graph.adjacencyList[v]; 23 | while (node) { 24 | if (!this.processed[node.y] || this.graph.isDirected) { 25 | this.processEdge?.(v, node.y, node.weight); 26 | } 27 | 28 | if (!this.discovered[node.y]) { 29 | this.discovered[node.y] = true; 30 | queue.push(node.y); 31 | this.parents[node.y] = v; 32 | } 33 | node = node.next; 34 | } 35 | this.processVertextLate?.(v); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /algorithms/graphs/Backtrack.mjs: -------------------------------------------------------------------------------- 1 | export default class Backtrack { 2 | consturctor() { 3 | this.isFinished = false; 4 | } 5 | 6 | execute(a, k, input) { 7 | if (this.isSolution(a, k, input)) { 8 | this?.processSolution(a, k); 9 | return; 10 | } 11 | 12 | k += 1; 13 | const candidates = this.constructCandidates(a, k, input); 14 | for (let i = 0; i < candidates.length; i++) { 15 | a[k] = candidates[i]; 16 | this.makeMove?.(a, k, input); 17 | this.execute(a, k, input); 18 | this.unmakeMove?.(a, k, input); 19 | 20 | if (this.isFinished) return; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /algorithms/graphs/DFS.mjs: -------------------------------------------------------------------------------- 1 | export default class DepthFirstSearch { 2 | time = 0; 3 | finished = false; 4 | 5 | constructor(graph) { 6 | this.graph = graph; 7 | this.parents = new Array(graph.vertices + 1); 8 | this.discovered = new Array(graph.vertices + 1); 9 | this.processed = new Array(graph.vertices + 1); 10 | this.entryTime = new Array(graph.vertices + 1); 11 | this.exitTime = new Array(graph.vertices + 1); 12 | } 13 | 14 | search(v) { 15 | if (this.finished) return; 16 | 17 | this.discovered[v] = true; 18 | this.time = this.time + 1; 19 | this.entryTime[v] = this.time; 20 | 21 | this.processVertexEarly?.(v); 22 | 23 | let node = this.graph.adjacencyList[v]; 24 | while (node) { 25 | if (!this.discovered[node.y]) { 26 | this.parents[node.y] = v; 27 | this.processEdge?.(v, node.y); 28 | this.search(node.y); 29 | } else if ((!this.processed[node.y] && this.parents[v] !== node.y) || this.graph.isDirected) { 30 | this.processEdge?.(v, node.y); 31 | } 32 | if (this.finished) return; 33 | node = node.next; 34 | } 35 | 36 | this.processVertextLate?.(v); 37 | 38 | this.time = this.time + 1; 39 | this.exitTime[v] = this.time; 40 | this.processed[v] = true; 41 | } 42 | } -------------------------------------------------------------------------------- /algorithms/search/BinarySearch.mjs: -------------------------------------------------------------------------------- 1 | export default class BinarySearch { 2 | 3 | constructor(array){ 4 | this.array = array; 5 | } 6 | 7 | getIndex(element) { 8 | let low = 0; 9 | let high = this.array.length - 1; 10 | let mid = Math.floor((low + high) / 2); 11 | 12 | while (low <= high) { 13 | if (this.array[mid] === element) return mid; 14 | if (this.array[mid] > element) high = mid - 1; 15 | else low = mid + 1; 16 | 17 | mid = Math.floor((low + high) / 2); 18 | } 19 | 20 | return -1; 21 | } 22 | 23 | getLeftBound(element) { 24 | let low = 0; 25 | let high = this.array.length - 1; 26 | let mid = Math.floor((low + high) / 2); 27 | 28 | while (low <= high) { 29 | if (element > this.array[mid]) low = mid + 1; 30 | else high = mid - 1; 31 | 32 | mid = Math.floor((low + high) / 2); 33 | } 34 | 35 | return low; 36 | } 37 | 38 | getRightBound(element) { 39 | let low = 0; 40 | let high = this.array.length - 1; 41 | let mid = Math.floor((low + high) / 2); 42 | 43 | while (low <= high) { 44 | if (element < this.array[mid]) high = mid - 1; 45 | else low = mid + 1; 46 | 47 | mid = Math.floor((low + high) / 2); 48 | } 49 | 50 | return low; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /algorithms/sorting/HeapSort.mjs: -------------------------------------------------------------------------------- 1 | export default class HeapSort { 2 | constructor(array = [], isMinHeap = true) { 3 | this.array = array; 4 | this.isMinHeap = isMinHeap; 5 | } 6 | 7 | sort() { 8 | for (let i = Math.floor(this.array.length / 2); i >= 0; i--) this.heapify(i); 9 | 10 | const sortedArray = []; 11 | while (this.array.length !== 1) { 12 | sortedArray.push(this.array[0]); 13 | this.array[0] = this.array.pop(); 14 | this.heapify(0); 15 | } 16 | this.array = sortedArray.concat(this.array); 17 | } 18 | 19 | insert(value) { 20 | this.array.push(value); 21 | this.bubbleUp(this.array.length - 1); 22 | return this.insert.bind(this); 23 | } 24 | 25 | bubbleUp(x) { 26 | const n = this.getParentIndex(x); 27 | if (n === -1) return; 28 | const siblings = this.getChildrenIndices(n); 29 | if (this.swapIfNeeded(n, siblings)) this.bubbleUp(n); 30 | } 31 | 32 | getParentIndex(x) { 33 | return Math.ceil(x / 2) - 1; 34 | } 35 | 36 | getChildrenIndices(n) { 37 | return [n * 2 + 1, n * 2 + 2]; 38 | } 39 | 40 | heapify(n) { 41 | const x = this.swapIfNeeded(n, this.getChildrenIndices(n)); 42 | if (x) this.heapify(x); 43 | } 44 | 45 | swapIfNeeded(n, [x, y]) { 46 | if (this.array[y] === undefined && this.comparator(n, x)) { 47 | this.swap(n, x); 48 | return x; 49 | } 50 | 51 | if (this.comparator(n, x) || this.comparator(n, y)) { 52 | if (this.comparator(x, y)) { 53 | this.swap(n, y); 54 | return y; 55 | } else { 56 | this.swap(n, x); 57 | return x; 58 | } 59 | } 60 | 61 | return false; 62 | } 63 | 64 | comparator(x, y) { 65 | return this.isMinHeap ? this.array[x] > this.array[y] : this.array[x] < this.array[y]; 66 | } 67 | 68 | swap(x, y) { 69 | const temp = this.array[x]; 70 | this.array[x] = this.array[y]; 71 | this.array[y] = temp; 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /algorithms/sorting/MergeSort.mjs: -------------------------------------------------------------------------------- 1 | export default class MergeSort { 2 | constructor(array) { 3 | this.array = array; 4 | } 5 | 6 | sort(array = this.array) { 7 | if (array.length === 1) return array; 8 | 9 | const arr1 = this.sort(array.slice(0, array.length / 2)); 10 | const arr2 = this.sort(array.slice(array.length / 2, array.length)); 11 | 12 | return this.merge(arr1, arr2); 13 | } 14 | 15 | merge(arr1, arr2) { 16 | const arr = []; 17 | let i = 0, 18 | j = 0; 19 | while (i < arr1.length && j < arr2.length) { 20 | if (arr1[i] < arr2[j]) { 21 | arr.push(arr1[i++]); 22 | } else { 23 | arr.push(arr2[j++]); 24 | } 25 | } 26 | 27 | while (i < arr1.length) arr.push(arr1[i++]); 28 | while (j < arr2.length) arr.push(arr2[j++]); 29 | 30 | return arr; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /algorithms/sorting/QuickSort.mjs: -------------------------------------------------------------------------------- 1 | export default class QuickSort { 2 | constructor(array) { 3 | this.array = array; 4 | } 5 | 6 | sort(pivot = 0, low = 0, high = this.array.length - 1) { 7 | if (low >= high) return; 8 | 9 | const p = this.partition(this.array, pivot, low, high); 10 | this.sort(low, low, p - 1); 11 | this.sort(p + 1, p + 1, high); 12 | } 13 | 14 | partition(array, pivot, low, high) { 15 | while (high >= low) { 16 | while (array[high] > array[pivot]) { 17 | high--; 18 | } 19 | while (array[low] <= array[pivot]) { 20 | low++; 21 | } 22 | 23 | if (low < high) [array[low], array[high]] = [array[high], array[low]]; 24 | } 25 | 26 | [array[high], array[pivot]] = [array[pivot], array[high]]; 27 | 28 | return high; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /data-structures/Graph.mjs: -------------------------------------------------------------------------------- 1 | class Edge { 2 | constructor(y, weight) { 3 | this.y = y; 4 | this.weight = weight; 5 | this.next = null; 6 | } 7 | 8 | add(e) { 9 | this.next = e; 10 | } 11 | 12 | hasNext() { 13 | return this.next !== null; 14 | } 15 | } 16 | 17 | export class Graph { 18 | constructor(vertices, isDirected) { 19 | this.vertices = vertices; 20 | this.degree = new Array(vertices + 1); 21 | this.isDirected = isDirected; 22 | this.edges = 0; 23 | this.adjacencyList = []; 24 | } 25 | 26 | insertEdges(edges) { 27 | edges.forEach((edge) => this.insertEdge(edge[0], edge[1], edge[2])); 28 | } 29 | 30 | insertEdge(x, y, weight = 1) { 31 | this.addEdge(x, y, weight); 32 | 33 | if (!this.isDirected) { 34 | this.addEdge(y, x, weight); 35 | } 36 | 37 | this.edges++; 38 | } 39 | 40 | addEdge(vertex1, vertex2, weight) { 41 | const list = this.adjacencyList[vertex1]; 42 | const e = new Edge(vertex2, weight); 43 | 44 | if (list) { 45 | e.next = list; 46 | } 47 | this.adjacencyList[vertex1] = e; 48 | this.degree[vertex1]++; 49 | } 50 | 51 | printGraph() { 52 | for (let i = 1; i <= this.vertices; i++) { 53 | let edge = this.adjacencyList[i]; 54 | 55 | let str = i; 56 | while (edge) { 57 | str += "->" + edge.y; 58 | edge = edge.next; 59 | } 60 | return str; 61 | } 62 | } 63 | 64 | displayDegree() { 65 | for (let i = 0; i < this.degree.length; i++) { 66 | console.log("Degree of node " + i + ": " + this.degree[i]); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /graphs JAVA/ArticulationPoint.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | public class ArticulationPoint extends GraphTraversal { 4 | 5 | int reachableAncestor[]; 6 | int treeOutDegree[]; 7 | 8 | ArticulationPoint(int vertices) { 9 | super(vertices); 10 | reachableAncestor = new int[vertices + 1]; 11 | treeOutDegree = new int[vertices + 1]; 12 | } 13 | 14 | public static void main(String[] args) { 15 | int vertices = 6; 16 | Graph graph = new Graph(vertices, false); 17 | 18 | graph.insertEdge(1, 2); 19 | graph.insertEdge(1, 5); 20 | graph.insertEdge(1, 6); 21 | 22 | graph.insertEdge(2, 5); 23 | graph.insertEdge(2, 3); 24 | 25 | graph.insertEdge(3, 4); 26 | graph.insertEdge(4, 5); 27 | 28 | ArticulationPoint dfs = new ArticulationPoint(vertices); 29 | dfs.depthFirstSearchRecursive(graph, 1); 30 | } 31 | 32 | public void processVertexEarly(int vertex) { 33 | reachableAncestor[vertex] = vertex; 34 | } 35 | 36 | public void processEdge(int x, int y) { 37 | String type = edgeClassification(x, y); 38 | if (type.equals("TREE")) 39 | treeOutDegree[x] = treeOutDegree[x] + 1; 40 | if (type.equals("BACK")) 41 | reachableAncestor[x] = y; 42 | } 43 | 44 | public void processVertexLate(int vertex) { 45 | exitTime[vertex] = ++time; 46 | 47 | boolean root; 48 | int timeV; 49 | int timeParent; 50 | 51 | if (parents[vertex] < 1) { 52 | if (treeOutDegree[vertex] > 1) 53 | System.out.printf("root articulation vertex: %d \n", vertex); 54 | return; 55 | } 56 | root = (parents[parents[vertex]] < 1); /* test if parent[v] is root */ 57 | if (!root) { 58 | if (reachableAncestor[vertex] == parents[vertex]) { 59 | System.out.printf("parent articulation vertex: %d \n", parents[vertex]); 60 | } 61 | if (reachableAncestor[vertex] == vertex) { 62 | System.out.printf("bridge articulation vertex: %d \n", parents[vertex]); 63 | if (treeOutDegree[vertex] > 0) /* test if v is not a leaf */ 64 | System.out.printf("bridge articulation vertex: %d \n", vertex); 65 | } 66 | } 67 | timeV = entryTime[reachableAncestor[vertex]]; 68 | timeParent = entryTime[reachableAncestor[parents[vertex]]]; 69 | if (timeV < timeParent) 70 | reachableAncestor[parents[vertex]] = reachableAncestor[vertex]; 71 | } 72 | 73 | public String edgeClassification(int x, int y) { 74 | if (parents[y] == x) 75 | return "TREE"; 76 | if (discovered[y] && !processed[y]) 77 | return "BACK"; 78 | if (processed[y] && (entryTime[y] > entryTime[x])) 79 | return "FORWARD"; 80 | if (processed[y] && (entryTime[y] < entryTime[x])) 81 | return "CROSS"; 82 | 83 | System.out.printf("Warning: unclassified edge (%d,%d)\n", x, y); 84 | return ""; 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /graphs JAVA/BFS.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | public class BFS extends GraphTraversal{ 4 | 5 | BFS(int vertices) { 6 | super(vertices); 7 | } 8 | 9 | public static void main(String[] args) { 10 | int vertices = 6; 11 | Graph graph = new Graph(vertices, false); 12 | 13 | graph.insertEdge(1, 2); 14 | graph.insertEdge(1, 5); 15 | graph.insertEdge(1, 6); 16 | 17 | graph.insertEdge(2, 5); 18 | graph.insertEdge(2, 3); 19 | 20 | graph.insertEdge(3, 4); 21 | graph.insertEdge(4, 5); 22 | 23 | BFS bfs = new BFS(vertices); 24 | System.out.println("Breadth First Search of the graph"); 25 | bfs.breadthFirstSearch(graph, 1); 26 | } 27 | 28 | @Override 29 | public void processVertexEarly(int x) { 30 | System.out.print(x + " "); 31 | } 32 | 33 | @Override 34 | public void processEdge(int x, int y){ 35 | 36 | } 37 | 38 | @Override 39 | public void processVertexLate(int y){ 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /graphs JAVA/BiPartite.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | public class BiPartite extends GraphTraversal{ 4 | 5 | int color[]; 6 | boolean bipartite = true; 7 | 8 | BiPartite(int vertices) { 9 | super(vertices); 10 | color = new int[vertices+1]; 11 | } 12 | 13 | public static void main(String[] args) { 14 | int vertices = 6; 15 | Graph graph = new Graph(vertices, false); 16 | 17 | graph.insertEdge(1, 2); 18 | graph.insertEdge(1, 4); 19 | graph.insertEdge(1, 6); 20 | 21 | graph.insertEdge(2, 3); 22 | graph.insertEdge(2, 5); 23 | 24 | graph.insertEdge(3, 4); 25 | graph.insertEdge(3, 6); 26 | 27 | graph.insertEdge(4, 5); 28 | graph.insertEdge(5, 6); 29 | 30 | BiPartite bfs = new BiPartite(vertices); 31 | 32 | bfs.color[1] = 1; 33 | bfs.breadthFirstSearch(graph, 1); 34 | 35 | if(bfs.bipartite) 36 | System.out.println("Graph is bipartite"); 37 | 38 | } 39 | 40 | public void processVertexEarly(int vertex) { 41 | 42 | } 43 | 44 | @Override 45 | public void processEdge(int vertex, int nextVertex){ 46 | if(color[vertex] == color[nextVertex]) { 47 | bipartite = false; 48 | System.out.println("Graph is not bipartite due to " + vertex + " and " + nextVertex); 49 | } 50 | color[nextVertex] = color[vertex] == 1 ? 2: 1; 51 | } 52 | 53 | @Override 54 | public void processVertexLate(int vertex){ 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /graphs JAVA/DFS.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | public class DFS extends GraphTraversal{ 4 | 5 | DFS(int vertices) { 6 | super(vertices); 7 | } 8 | 9 | public static void main(String[] args) { 10 | int vertices = 6; 11 | Graph graph = new Graph(vertices, false); 12 | 13 | graph.insertEdge(1, 2); 14 | graph.insertEdge(1, 5); 15 | graph.insertEdge(1, 6); 16 | 17 | graph.insertEdge(2, 5); 18 | graph.insertEdge(2, 3); 19 | 20 | graph.insertEdge(3, 4); 21 | graph.insertEdge(4, 5); 22 | 23 | DFS dfs = new DFS(vertices); 24 | System.out.println("Depth First Search of the graph"); 25 | dfs.depthFirstSearchRecursive(graph, 1); 26 | 27 | System.out.println(); 28 | dfs.displayNodeTime(); 29 | } 30 | 31 | @Override 32 | public void processVertexEarly(int vertex) { 33 | System.out.print(vertex + " "); 34 | } 35 | 36 | @Override 37 | public void processEdge(int vertex, int nextVertex){ 38 | 39 | } 40 | 41 | @Override 42 | public void processVertexLate(int vertex){ 43 | } 44 | 45 | public void displayNodeTime() { 46 | System.out.println(); 47 | for (int i = 1; i < entryTime.length; i++) { 48 | System.out.println("Node time " + i + ": " + entryTime[i] + "-" + exitTime[i]); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /graphs JAVA/DFSCycleDetection.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | public class DFSCycleDetection extends GraphTraversal { 4 | 5 | DFSCycleDetection(int vertices) { 6 | super(vertices); 7 | } 8 | 9 | public static void main(String[] args) { 10 | int vertices = 6; 11 | Graph graph = new Graph(vertices, false); 12 | 13 | graph.insertEdge(1, 2); 14 | graph.insertEdge(1, 5); 15 | graph.insertEdge(1, 6); 16 | 17 | graph.insertEdge(2, 5); 18 | graph.insertEdge(2, 3); 19 | 20 | graph.insertEdge(3, 4); 21 | graph.insertEdge(4, 5); 22 | 23 | DFSCycleDetection dfs = new DFSCycleDetection(vertices); 24 | 25 | dfs.depthFirstSearchRecursive(graph, 1); 26 | } 27 | 28 | public void processVertexEarly(int vertex) { 29 | 30 | } 31 | 32 | public void processEdge(int x, int y) { 33 | if (discovered[y] && (parents[x] != y)) { 34 | System.out.println("Cycle from " + y + " to " + x); 35 | findPath(y, x); 36 | finished = true; // comment it to get all the cycles 37 | } 38 | } 39 | 40 | public void processVertexLate(int vertex) { 41 | 42 | } 43 | 44 | public void findPath(int x, int y) { 45 | if (x == y || y == 0) { 46 | System.out.println(y); 47 | return; 48 | } else { 49 | System.out.print(y + "->"); 50 | findPath(x, parents[y]); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /graphs JAVA/Graph.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import java.util.*; 4 | 5 | class Edge{ 6 | int y; 7 | int weight; 8 | 9 | Edge(int y, int weight){ 10 | this.y = y; 11 | this.weight = weight; 12 | } 13 | 14 | public String toString() { 15 | return String.valueOf(y); 16 | } 17 | } 18 | 19 | public class Graph { 20 | 21 | int vertices; 22 | int degree[]; 23 | boolean directed; 24 | int edges; 25 | ArrayList> adjacencyList; 26 | 27 | public Graph(int vertices, boolean directed) { 28 | this.vertices = vertices; 29 | this.degree = new int[vertices + 1]; 30 | this.directed = directed; 31 | this.edges = 0; 32 | this.adjacencyList = new ArrayList>(); 33 | 34 | for (int i = 0; i <= vertices; i++) 35 | this.adjacencyList.add(new LinkedList()); 36 | } 37 | 38 | public void insertEdge(int x, int y) { 39 | insertEdge(x, y, 1); 40 | } 41 | 42 | public void insertEdge(int x, int y, int weight) { 43 | adjacencyList.get(x).add(new Edge(y, weight)); 44 | degree[x]++; 45 | 46 | if (!directed) { 47 | adjacencyList.get(y).add(new Edge(x, weight)); 48 | degree[y]++; 49 | } 50 | 51 | edges++; 52 | } 53 | 54 | public void printGraph() { 55 | for (int i = 1; i <= vertices; i++) { 56 | Iterator it = adjacencyList.get(i).iterator(); 57 | 58 | System.out.print(i); 59 | while (it.hasNext()) 60 | System.out.print("->" + it.next()); 61 | System.out.println(); 62 | } 63 | } 64 | 65 | public void displayDegree() { 66 | for (int i = 0; i < degree.length; i++) { 67 | System.out.println("Degree of node " + i + ": " + degree[i]); 68 | } 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /graphs JAVA/GraphTraversal.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedList; 5 | import java.util.Stack; 6 | 7 | public abstract class GraphTraversal { 8 | 9 | int vertices; 10 | boolean discovered[]; 11 | boolean processed[]; 12 | int parents[]; 13 | boolean finished = false; 14 | int entryTime[], exitTime[], time = 0; 15 | 16 | GraphTraversal(int vertices) { 17 | this.vertices = vertices; 18 | discovered = new boolean[vertices + 1]; 19 | processed = new boolean[vertices + 1]; 20 | parents = new int[vertices + 1]; 21 | entryTime = new int[vertices + 1]; 22 | exitTime = new int[vertices + 1]; 23 | } 24 | 25 | public void breadthFirstSearch(Graph graph, int vertex) { 26 | LinkedList queue = new LinkedList(); 27 | queue.offer(vertex); 28 | discovered[vertex] = true; 29 | 30 | while (!queue.isEmpty()) { 31 | int x = queue.poll(); 32 | 33 | processVertexEarly(x); 34 | processed[x] = true; 35 | 36 | Iterator it = graph.adjacencyList.get(x).iterator(); 37 | while (it.hasNext()) { 38 | int y = it.next().y; 39 | 40 | if (!processed[y] || graph.directed) 41 | processEdge(x, y); 42 | 43 | if (!discovered[y]) { 44 | queue.offer(y); 45 | discovered[y] = true; 46 | parents[y] = x; 47 | } 48 | } 49 | processVertexLate(x); 50 | } 51 | } 52 | 53 | public void depthFirstSearch(Graph graph, int vertex) { 54 | Stack stack = new Stack(); 55 | stack.push(vertex); 56 | discovered[vertex] = true; 57 | 58 | while (!stack.isEmpty()) { 59 | int x = stack.pop(); 60 | processVertexEarly(x); 61 | 62 | Iterator it = graph.adjacencyList.get(x).iterator(); 63 | while (it.hasNext()) { 64 | int y = it.next().y; 65 | parents[y] = x; 66 | 67 | if (!discovered[y]) { 68 | stack.push(y); 69 | processEdge(x, y); 70 | discovered[y] = true; 71 | } else if ((!processed[y] && parents[x] != y) || graph.directed) 72 | processEdge(x, y); 73 | 74 | if (finished) 75 | return; 76 | } 77 | processed[x] = true; 78 | processVertexLate(x); 79 | } 80 | } 81 | 82 | public void depthFirstSearchRecursive(Graph graph, int vertex) { 83 | discovered[vertex] = true; 84 | entryTime[vertex] = ++time; 85 | processVertexEarly(vertex); 86 | 87 | Iterator it = graph.adjacencyList.get(vertex).iterator(); 88 | while (it.hasNext()) { 89 | int y = it.next().y; 90 | 91 | if (!discovered[y]) { 92 | parents[y] = vertex; 93 | processEdge(vertex, y); 94 | depthFirstSearchRecursive(graph, y); 95 | } else if ((!processed[y] && parents[vertex] != y) || graph.directed) 96 | processEdge(vertex, y); 97 | 98 | if (finished) 99 | return; 100 | } 101 | exitTime[vertex] = ++time; 102 | processed[vertex] = true; 103 | processVertexLate(vertex); 104 | } 105 | 106 | abstract public void processVertexEarly(int x); 107 | 108 | abstract public void processEdge(int x, int y); 109 | 110 | abstract public void processVertexLate(int x); 111 | 112 | } -------------------------------------------------------------------------------- /graphs JAVA/ShortestDistance.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | public class ShortestDistance extends GraphTraversal{ 4 | 5 | ShortestDistance(int vertices) { 6 | super(vertices); 7 | } 8 | 9 | public static void main(String[] args) { 10 | int vertices = 6; 11 | Graph graph = new Graph(vertices, false); 12 | 13 | graph.insertEdge(1, 2); 14 | graph.insertEdge(1, 5); 15 | graph.insertEdge(1, 6); 16 | 17 | graph.insertEdge(2, 5); 18 | graph.insertEdge(2, 3); 19 | 20 | graph.insertEdge(3, 4); 21 | graph.insertEdge(4, 5); 22 | 23 | ShortestDistance bfs = new ShortestDistance(vertices); 24 | bfs.breadthFirstSearch(graph, 6); 25 | 26 | System.out.println("Shortest distance from 1 to 4"); 27 | bfs.findPath(6, 4); 28 | } 29 | 30 | @Override 31 | public void processVertexEarly(int x) { 32 | 33 | } 34 | 35 | @Override 36 | public void processEdge(int x, int y){ 37 | 38 | } 39 | 40 | @Override 41 | public void processVertexLate(int y){ 42 | 43 | } 44 | 45 | public void findPath(int x, int y) { 46 | if (x == y || y == 0) { 47 | System.out.println(y); 48 | return; 49 | } else { 50 | System.out.print(y + "->"); 51 | findPath(x, parents[y]); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /graphs JAVA/StrongComponents.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import java.util.Stack; 4 | 5 | public class StrongComponents extends GraphTraversal { 6 | 7 | public Stack stack; 8 | public int low[]; 9 | public int scc[]; 10 | public int componentsFound = 0; 11 | 12 | StrongComponents(int vertices) { 13 | super(vertices); 14 | stack = new Stack(); 15 | low = new int[vertices + 1]; /* oldest vertex surely in component of v */ 16 | scc = new int[vertices + 1]; /* strong component number for each vertex */ 17 | } 18 | 19 | public static void main(String[] args) { 20 | int vertices = 8; 21 | Graph graph = new Graph(vertices, true); 22 | 23 | graph.insertEdge(1, 2); 24 | graph.insertEdge(2, 3); 25 | graph.insertEdge(3, 1); 26 | graph.insertEdge(2, 4); 27 | graph.insertEdge(2, 5); 28 | 29 | graph.insertEdge(4, 1); 30 | graph.insertEdge(4, 8); 31 | graph.insertEdge(4, 6); 32 | graph.insertEdge(8, 6); 33 | 34 | graph.insertEdge(5, 6); 35 | graph.insertEdge(6, 7); 36 | graph.insertEdge(7, 5); 37 | 38 | StrongComponents dfs = new StrongComponents(vertices); 39 | for (int i = 1; i <= vertices; i++) { 40 | dfs.low[i] = i; 41 | dfs.scc[i] = -1; 42 | } 43 | 44 | for (int i = 1; i <= vertices; i++) { 45 | if (!dfs.discovered[i]) { 46 | dfs.depthFirstSearchRecursive(graph, i); 47 | } 48 | } 49 | 50 | for (int i = 1; i <= vertices; i++) { 51 | System.out.println("vertex " + i + " belongs to component " + dfs.scc[i]); 52 | } 53 | } 54 | 55 | @Override 56 | public void processVertexEarly(int x) { 57 | stack.push(x); 58 | } 59 | 60 | @Override 61 | public void processEdge(int x, int y) { 62 | String type = edgeClassification(x, y); 63 | if (type.equals("BACK")) { 64 | if (entryTime[y] < entryTime[low[x]]) 65 | low[x] = y; 66 | } 67 | if (type.equals("CROSS")) { 68 | if (scc[y] == -1) 69 | if (entryTime[y] < entryTime[low[x]]) 70 | low[x] = y; 71 | } 72 | } 73 | 74 | @Override 75 | public void processVertexLate(int x) { 76 | if (low[x] == x) 77 | popComponent(x); 78 | 79 | if (parents[x] > 0) 80 | if (entryTime[low[x]] < entryTime[low[parents[x]]]) 81 | low[parents[x]] = low[x]; 82 | } 83 | 84 | private void popComponent(int x) { 85 | int t; 86 | componentsFound++;; 87 | scc[x] = componentsFound; 88 | while (!stack.isEmpty()) { 89 | t = stack.pop(); 90 | if(t != x) 91 | scc[t] = componentsFound; 92 | else break; 93 | } 94 | } 95 | 96 | public String edgeClassification(int x, int y) { 97 | if (parents[y] == x) 98 | return "TREE"; 99 | if (discovered[y] && !processed[y]) 100 | return "BACK"; 101 | if (processed[y] && (entryTime[y] > entryTime[x])) 102 | return "FORWARD"; 103 | if (processed[y] && (entryTime[y] < entryTime[x])) 104 | return "CROSS"; 105 | 106 | System.out.printf("Warning: unclassified edge (%d,%d)\n", x, y); 107 | return ""; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /graphs JAVA/TopologicalSort.java: -------------------------------------------------------------------------------- 1 | package graphs; 2 | 3 | import java.util.Stack; 4 | 5 | public class TopologicalSort extends GraphTraversal { 6 | 7 | Stack topoStack = new Stack(); 8 | 9 | TopologicalSort(int vertices) { 10 | super(vertices); 11 | } 12 | 13 | public static void main(String[] args) { 14 | int vertices = 7; 15 | Graph graph = new Graph(vertices, true); 16 | 17 | graph.insertEdge(1, 2); 18 | graph.insertEdge(1, 3); 19 | 20 | graph.insertEdge(2, 3); 21 | graph.insertEdge(2, 4); 22 | 23 | graph.insertEdge(3, 5); 24 | graph.insertEdge(3, 6); 25 | 26 | graph.insertEdge(5, 4); 27 | graph.insertEdge(6, 5); 28 | 29 | graph.insertEdge(7, 1); 30 | graph.insertEdge(7, 6); 31 | 32 | TopologicalSort dfs = new TopologicalSort(vertices); 33 | 34 | for (int i = 1; i <= vertices; i++) 35 | if (!dfs.discovered[i]) 36 | dfs.depthFirstSearchRecursive(graph, i); 37 | 38 | dfs.displayTopoSort(); 39 | } 40 | 41 | public void processVertexEarly(int vertex) { 42 | 43 | } 44 | 45 | public void processEdge(int vertex, int nextVertex) { 46 | 47 | } 48 | 49 | public void processVertexLate(int vertex) { 50 | topoStack.push(vertex); 51 | } 52 | 53 | public void displayTopoSort() { 54 | while(!topoStack.isEmpty()) 55 | System.out.print(topoStack.pop() + " "); 56 | 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /implementations/backtracking/allPaths.mjs: -------------------------------------------------------------------------------- 1 | import Backtrack from "../../algorithms/graphs/Backtrack.mjs"; 2 | import { Graph } from "../../data-structures/Graph.mjs"; 3 | 4 | const vertices = 6; 5 | const source = 1, destination = 3; 6 | const g = new Graph(vertices, false); 7 | g.insertEdges([ 8 | [1, 2], 9 | [1, 3], 10 | [1, 4], 11 | [1, 5], 12 | [2, 6], 13 | [3, 6], 14 | [4, 6], 15 | [5, 6], 16 | [3, 4], 17 | ]); 18 | 19 | const backtrack = new Backtrack(); 20 | 21 | backtrack.isSolution = (a, k) => a[k] === destination; 22 | 23 | backtrack.constructCandidates = function (a, k) { 24 | if (k === 0) { 25 | return [source]; 26 | } 27 | 28 | a.fill(undefined, k); 29 | const candidates = []; 30 | let edge = g.adjacencyList[a[k - 1]]; 31 | while (edge) { 32 | if (!a.includes(edge.y)) { 33 | candidates.push(edge.y); 34 | } 35 | edge = edge.next; 36 | } 37 | 38 | return candidates; 39 | }; 40 | 41 | backtrack.processSolution = function (a, k) { 42 | console.log(a.slice(0, k + 1)); 43 | }; 44 | 45 | console.log(`Paths from ${source} to ${destination}`); 46 | backtrack.execute([], -1, 6); 47 | -------------------------------------------------------------------------------- /implementations/backtracking/derangements.mjs: -------------------------------------------------------------------------------- 1 | import Backtrack from "../../algorithms/graphs/Backtrack.mjs"; 2 | 3 | const backtrack = new Backtrack(); 4 | 5 | backtrack.isSolution = (_, k, n) => k === n; 6 | 7 | backtrack.constructCandidates = function (a, k, n) { 8 | const set = new Set(a.slice(1, k)); 9 | const candidates = []; 10 | for (let i = 1; i <= n; i++) { 11 | if (!set.has(i) && i !== k) { 12 | candidates.push(i); 13 | } 14 | } 15 | return candidates; 16 | }; 17 | 18 | backtrack.processSolution = function (a) { 19 | console.log(a.slice(1)); 20 | }; 21 | 22 | backtrack.execute([], 0, 4); 23 | -------------------------------------------------------------------------------- /implementations/backtracking/multisetPermutation.mjs: -------------------------------------------------------------------------------- 1 | import Backtrack from "../../algorithms/graphs/Backtrack.mjs"; 2 | 3 | const backtrack = new Backtrack(); 4 | 5 | backtrack.isSolution = (_, k, input) => k >= input.length; 6 | 7 | backtrack.constructCandidates = function (a, k, input) { 8 | const array = a.slice(1, k); 9 | const candidates = new Set(); 10 | for (let i = 0; i < input.length; i++) { 11 | const index = array.indexOf(input[i]); 12 | if (index < 0) { 13 | candidates.add(input[i]); 14 | } else { 15 | delete array[index]; 16 | } 17 | } 18 | 19 | return [...candidates]; 20 | }; 21 | 22 | backtrack.processSolution = function (a) { 23 | console.log(a.slice(1)); 24 | }; 25 | 26 | backtrack.execute([], 0, [1, 1, 2, 2]); 27 | -------------------------------------------------------------------------------- /implementations/backtracking/permutation.mjs: -------------------------------------------------------------------------------- 1 | import Backtrack from "../../algorithms/graphs/Backtrack.mjs"; 2 | 3 | const backtrack = new Backtrack([], -1, 3); 4 | 5 | backtrack.isSolution = (_, k, n) => k === n; 6 | 7 | backtrack.constructCandidates = function (a, k, n) { 8 | const set = new Set(a.slice(0, k)); 9 | const candidates = []; 10 | for (let i = 1; i <= n; i++) { 11 | if (!set.has(i)) { 12 | candidates.push(i); 13 | } 14 | } 15 | return candidates; 16 | }; 17 | 18 | backtrack.processSolution = function (a, k) { 19 | let str = ""; 20 | for (let i = 1; i <= k; i++) str += a[i]; 21 | console.log(str); 22 | }; 23 | 24 | backtrack.execute([], 0, 3); 25 | -------------------------------------------------------------------------------- /implementations/backtracking/subset.mjs: -------------------------------------------------------------------------------- 1 | import Backtrack from "../../algorithms/graphs/Backtrack.mjs"; 2 | 3 | const backtrack = new Backtrack([], -1, 3); 4 | 5 | backtrack.isSolution = function (a, k, n) { 6 | return k === n; 7 | }; 8 | 9 | backtrack.constructCandidates = function (a, k, n, candidates) { 10 | return [true, false]; 11 | }; 12 | 13 | backtrack.processSolution = function (a, k) { 14 | let str = ""; 15 | 16 | for (let i = 1; i <= k; i++) if (a[i]) str += i; 17 | console.log("{" + str + "}"); 18 | }; 19 | 20 | backtrack.execute([], 0, 3); 21 | -------------------------------------------------------------------------------- /implementations/backtracking/sudoku.mjs: -------------------------------------------------------------------------------- 1 | class Sudoku { 2 | constructor(board) { 3 | this.board = board; 4 | this.m = Math.floor(Math.sqrt(board.length)); 5 | this.n = board.length / this.m; 6 | this.length = board.length; 7 | this.isFinished = false; 8 | } 9 | 10 | search(x = 0, y = 0) { 11 | if (y === this.length) { 12 | y = 0; 13 | x += 1; 14 | 15 | if (x === this.length) { 16 | console.log("Found solution"); 17 | console.log(this.board); 18 | // this.isFinished = true; 19 | return; 20 | } 21 | } 22 | 23 | if (this.board[x][y] !== 0) { 24 | y += 1; 25 | this.search(x, y); 26 | return; 27 | } 28 | 29 | const candidates = this.constructCandidates(this.board, x, y, this.m, this.n); 30 | for (let i = 0; i < candidates.length; i++) { 31 | this.board[x][y] = candidates[i]; 32 | this.search(x, y + 1); 33 | this.board[x][y] = 0; 34 | 35 | if (this.isFinished) return; 36 | } 37 | } 38 | 39 | constructCandidates(board, x, y, m, n) { 40 | const set = new Set([ 41 | ...this.getRowElements(board, x), 42 | ...this.getColElements(board, y), 43 | ...this.getBoxElements(board, x, y, m, n), 44 | ]); 45 | 46 | const elements = []; 47 | for (let i = 1; i <= board.length; i++) { 48 | if (!set.has(i)) { 49 | elements.push(i); 50 | } 51 | } 52 | return elements; 53 | } 54 | 55 | getRowElements = (board, x) => board[x].filter((v) => v); 56 | getColElements = (board, y) => board.map((row) => row[y]).filter((v) => v); 57 | getBoxElements = (board, x, y, m, n) => { 58 | const row = Math.floor(x / m) * m; 59 | const col = Math.floor(y / n) * n; 60 | 61 | const elements = []; 62 | for (let i = row; i < row + m; i++) { 63 | for (let j = col; j < col + n; j++) { 64 | elements.push(board[i][j]); 65 | } 66 | } 67 | return elements; 68 | }; 69 | } 70 | 71 | 72 | 73 | const board = [ 74 | [0, 0, 0, 0, 0, 0, 0, 1, 2], 75 | [0, 0, 0, 0, 3, 5, 0, 0, 0], 76 | [0, 0, 0, 6, 0, 0, 0, 7, 0], 77 | [7, 0, 0, 0, 0, 0, 3, 0, 0], 78 | [0, 0, 0, 4, 0, 0, 8, 0, 0], 79 | [1, 0, 0, 0, 0, 0, 0, 0, 0], 80 | [0, 0, 0, 1, 2, 0, 0, 0, 0], 81 | [0, 8, 0, 0, 0, 0, 0, 4, 0], 82 | [0, 5, 0, 0, 0, 0, 6, 0, 0], 83 | ]; 84 | 85 | console.time(); 86 | new Sudoku(board).search(); 87 | console.timeEnd(); 88 | -------------------------------------------------------------------------------- /implementations/dynamic-programming/binomial-coefficient.mjs: -------------------------------------------------------------------------------- 1 | const f = [[1]]; 2 | 3 | function binoCo(n, k) { 4 | for (let i = 1; i <= n; i++) { 5 | f.push([]); 6 | for (let j = 0; j <= i; j++) { 7 | f[i][j] = (f[i - 1][j - 1] ?? 0) + (f[i - 1][j] ?? 0); 8 | } 9 | } 10 | return f[n][k]; 11 | } 12 | 13 | console.log(binoCo(12, 8)); 14 | -------------------------------------------------------------------------------- /implementations/dynamic-programming/edit-distance.mjs: -------------------------------------------------------------------------------- 1 | const w1 = "horse"; 2 | const w2 = "hello"; 3 | 4 | const mem = Array.from(new Array(w1.length), (_) => []); 5 | function minDistanceMem(w1, w2, i, j) { 6 | if (!w1) return w2.length; 7 | if (!w2) return w1.length; 8 | 9 | if (mem[i]?.[j] !== undefined) return mem[i][j]; 10 | 11 | if (w1[0] === w2[0]) { 12 | return minDistanceMem(w1.substring(1), w2.substring(1), i + 1, j + 1); 13 | } 14 | 15 | const insert = 1 + minDistanceMem(w1, w2.substring(1), i, j + 1); 16 | const remove = 1 + minDistanceMem(w1.substring(1), w2, i + 1, j); 17 | const replace = 1 + minDistanceMem(w1.substring(1), w2.substring(1), i + 1, j + 1); 18 | 19 | const min = Math.min(insert, remove, replace); 20 | mem[i][j] = min; 21 | 22 | return min; 23 | } 24 | 25 | const table = Array.from(new Array(w1.length + 1), (_) => []); 26 | const parents = Array.from(new Array(w1.length + 1), (_) => []); 27 | function minDistanceTabulation(w1, w2) { 28 | if (!w1 && !w2) return 0; 29 | if (!w1) return w2.length; 30 | if (!w2) return w1.length; 31 | 32 | table[0][0] = 0; 33 | for (let i = 0; i <= w1.length; i++) {table[i][0] = i; parents[i][0] = 'DEL'; } 34 | for (let j = 0; j <= w2.length; j++) {table[0][j] = j; parents[0][j] = 'INS'; } 35 | parents[0][0] = -1; 36 | 37 | for(let i = 1; i <= w1.length; i++) { 38 | for (let j = 1; j <= w2.length; j++){ 39 | const insert = 1 + table[i][j-1]; 40 | const remove = 1 + table[i-1][j]; 41 | const replace = table[i-1][j-1] + (w1[i-1] !== w2[j-1]); 42 | 43 | table[i][j] = Math.min(insert, remove, replace); 44 | parents[i][j] = table[i][j] === insert ? 'INS' : (table[i][j] === remove ? 'DEL' : 'REP'); 45 | } 46 | } 47 | 48 | consturctPath(parents, w1.length, w2.length); 49 | 50 | return table[w1.length][w2.length]; 51 | } 52 | 53 | function consturctPath(parents, i, j){ 54 | 55 | if(parents[i][j] === -1) return; 56 | 57 | if(parents[i][j] === 'REP'){ 58 | consturctPath(parents, i-1, j-1); 59 | if(w1[i-1] !== w2[j-1]){ 60 | console.log(`Replace ${w1[i-1]} with ${w2[j-1]}`); 61 | } 62 | return; 63 | } 64 | 65 | if(parents[i][j] === 'INS'){ 66 | consturctPath(parents, i, j-1); 67 | console.log(`Insert ${w2[j-1]}`); 68 | return; 69 | } 70 | 71 | if(parents[i][j] === 'DEL'){ 72 | consturctPath(parents, i-1, j); 73 | console.log(`Delete ${w1[i-1]}`); 74 | return; 75 | } 76 | 77 | } 78 | 79 | // console.log(minDistanceMem(w1, w2, 0, 0)); 80 | console.log('Minimum distance is ' + minDistanceTabulation(w1, w2, 0, 0)); -------------------------------------------------------------------------------- /implementations/dynamic-programming/fibonacci.mjs: -------------------------------------------------------------------------------- 1 | const table = [0, 1]; 2 | function fibTabulation(n) { 3 | if (n < 2) { 4 | return table[n]; 5 | } 6 | 7 | for (let i = 2; i <= n; i++) { 8 | table[i] = table[i - 1] + table[i - 2]; 9 | } 10 | 11 | return table[n]; 12 | } 13 | 14 | const mem = [0, 1]; 15 | function fibMemoization(n) { 16 | if (n < 2) { 17 | return mem[n]; 18 | } 19 | 20 | mem[n] = fibMemoization(n - 1) + fibTabulation(n - 2); 21 | return mem[n]; 22 | } 23 | 24 | console.log(fibTabulation(8)); 25 | console.log(fibMemoization(8)); 26 | -------------------------------------------------------------------------------- /implementations/graphs/Dijkstra.mjs: -------------------------------------------------------------------------------- 1 | import { Graph } from "../../data-structures/Graph.mjs"; 2 | import Heap from "@datastructures-js/priority-queue"; 3 | 4 | const vertices = 6; 5 | const g = new Graph(vertices, false); 6 | g.insertEdges([ 7 | [1, 6, 2], 8 | [1, 5, 1], 9 | [1, 2, 3], 10 | [2, 5, 6], 11 | [2, 3, 3], 12 | [3, 4, 5], 13 | [4, 5, 4], 14 | ]); 15 | 16 | const minPQ = new Heap.PriorityQueue({ 17 | compare: (e1, e2) => { 18 | if (e1.rank > e2.rank) return 1; 19 | if (e1.rank < e2.rank) return -1; 20 | }, 21 | }); 22 | 23 | const distance = dijkstra(g, 1); 24 | console.log(distance); 25 | 26 | function dijkstra(g, start) { 27 | const distance = new Array(g.vertices + 1).fill(Number.MAX_SAFE_INTEGER); 28 | const discovered = new Array(g.vertices + 1).fill(false); 29 | const isRelaxed = new Array(g.vertices + 1).fill(false); 30 | 31 | distance[start] = 0; 32 | let node = { vertex: start, rank: 0 }; 33 | minPQ.enqueue(node); 34 | 35 | while (minPQ.size()) { 36 | const node = minPQ.dequeue(); 37 | start = node.vertex; 38 | 39 | if(isRelaxed[start]) continue; 40 | 41 | let edge = g.adjacencyList[start]; 42 | while (edge) { 43 | if (!isRelaxed[edge.y]) { 44 | if (distance[edge.y] > distance[start] + edge.weight) { 45 | distance[edge.y] = distance[start] + edge.weight; 46 | } 47 | 48 | if (!discovered[edge.y]) { 49 | minPQ.enqueue({ vertex: edge.y, rank: distance[edge.y] }); 50 | discovered[edge.y] = true; 51 | } 52 | } 53 | edge = edge.next; 54 | } 55 | 56 | isRelaxed[start] = true; 57 | } 58 | 59 | return distance; 60 | } 61 | -------------------------------------------------------------------------------- /implementations/graphs/Kruskal.mjs: -------------------------------------------------------------------------------- 1 | import { Graph } from "../../data-structures/Graph.mjs"; 2 | import BFS from "../../algorithms/graphs/BFS.mjs"; 3 | 4 | const vertices = 6; 5 | const parents = Array.from(new Array(vertices + 1), (_, idx) => idx); 6 | const size = new Array(vertices + 1).fill(1); 7 | 8 | const find = (x) => (parents[x] === x ? x : find(parents[x])); 9 | const union = (s1, s2) => { 10 | let r1 = find(s1); 11 | let r2 = find(s2); 12 | 13 | if (r1 == r2) return; 14 | 15 | if (size[r1] >= size[r2]) { 16 | size[r1] = size[r1] + size[r2]; 17 | parents[r2] = r1; 18 | } else { 19 | size[r2] = size[r1] + size[r2]; 20 | parents[r1] = r2; 21 | } 22 | }; 23 | 24 | const g = new Graph(vertices, false); 25 | g.insertEdges([ 26 | [1, 6, 2], 27 | [1, 5, 1], 28 | [1, 2, 3], 29 | [2, 5, 6], 30 | [2, 3, 3], 31 | [3, 4, 5], 32 | [4, 5, 4], 33 | ]); 34 | const bfs = new BFS(g, 1); 35 | 36 | const edges = []; 37 | bfs.processEdge = function (x, y, weight) { 38 | edges.push({ x, y, weight }); 39 | }; 40 | bfs.search(1); 41 | edges.sort((a, b) => a.weight - b.weight); 42 | 43 | let dist = 0; 44 | for (let i = 0; i < edges.length; i++) { 45 | if(find(edges[i].x) !== find(edges[i].y)){ 46 | dist += edges[i].weight; 47 | console.log(`Edge: ${edges[i].x} -> ${edges[i].y}`); 48 | union(edges[i].x, edges[i].y); 49 | } 50 | } 51 | 52 | console.log('Minimum spanning distance: ' + dist); -------------------------------------------------------------------------------- /implementations/graphs/Prims.mjs: -------------------------------------------------------------------------------- 1 | import { Graph } from "../../data-structures/Graph.mjs"; 2 | 3 | function prim(g, start) { 4 | const isInTree = new Array(g.vertices + 1); 5 | const distance = new Array(g.vertices + 1).fill(Number.MAX_SAFE_INTEGER); 6 | const parents = new Array(g.vertices + 1); 7 | let minSpanDistance = 0; 8 | 9 | distance[start] = 0; 10 | parents[start] = -1; 11 | let v = start; 12 | while (!isInTree[v]) { 13 | isInTree[v] = true; 14 | 15 | let p = g.adjacencyList[v]; 16 | while (p !== null) { 17 | let w = p.y; 18 | let weight = p.weight; 19 | 20 | if (distance[w] > weight && !isInTree[w]) { 21 | distance[w] = weight; 22 | parents[w] = v; 23 | } 24 | p = p.next; 25 | } 26 | 27 | v = 1; 28 | let dist = Number.MAX_SAFE_INTEGER; 29 | for (let i = 1; i <= g.vertices; i++) { 30 | if (!isInTree[i] && dist > distance[i]) { 31 | dist = distance[i]; 32 | v = i; 33 | } 34 | } 35 | 36 | if (v !== start) { 37 | minSpanDistance += dist; 38 | console.log('Edge: ' + parents[v] + '->' + v); 39 | } 40 | } 41 | 42 | return minSpanDistance; 43 | } 44 | 45 | const vertices = 6; 46 | const g = new Graph(vertices, false); 47 | g.insertEdges([ 48 | [1, 6, 2], 49 | [1, 5, 1], 50 | [1, 2, 3], 51 | [2, 5, 6], 52 | [2, 3, 3], 53 | [3, 4, 5], 54 | [4, 5, 4], 55 | ]); 56 | const minSpanDistance = prim(g, 1); 57 | console.log("Minimum spanning distance: " + minSpanDistance); 58 | -------------------------------------------------------------------------------- /implementations/graphs/articulationPoint.mjs: -------------------------------------------------------------------------------- 1 | import { Graph } from "../../data-structures/Graph.mjs"; 2 | import DFS from "../../algorithms/graphs/DFS.mjs"; 3 | 4 | const vertices = 6; 5 | const g = new Graph(vertices, false); 6 | g.insertEdges([[1, 6],[1, 5],[1, 2],[2, 5],[2, 3],[3, 4],[4, 5]]); 7 | 8 | const dfs = new DFS(g); 9 | 10 | dfs.processVertexEarly = function (v) { 11 | reachableAncestor[v] = v; 12 | }; 13 | 14 | dfs.processEdge = function (x, y) { 15 | if (this.parents[y] == x) { 16 | treeOutDegree[x] = treeOutDegree[x] + 1; 17 | } 18 | 19 | if (this.discovered[y] && !this.processed[y] && this.parents[x] !== y) { 20 | if (this.entryTime[y] < this.entryTime[reachableAncestor[x]]) { 21 | reachableAncestor[x] = y; 22 | } 23 | } 24 | }; 25 | 26 | dfs.processVertextLate = function (v) { 27 | let isRoot; 28 | let timeV; 29 | let timeParent; 30 | 31 | if (this.parents[v] < 1) { 32 | if (treeOutDegree[v] > 1) { 33 | console.log(`root articulation vertex: ${v}`); 34 | } 35 | return; 36 | } 37 | 38 | isRoot = (this.parents[this.parents[v]] < 1); 39 | 40 | if (!isRoot) { 41 | if (reachableAncestor[v] == this.parents[v]) { 42 | console.log(`parent articulation vertex: ${this.parents[v]}`); 43 | } 44 | if (reachableAncestor[v] == v) { 45 | console.log(`bridge articulation vertex: ${this.parents[v]}`); 46 | if (treeOutDegree[v] > 0) 47 | console.log(`bridge articulation vertex: ${v}`); 48 | } 49 | } 50 | timeV = this.entryTime[reachableAncestor[v]]; 51 | timeParent = this.entryTime[reachableAncestor[this.parents[v]]]; 52 | if (timeV < timeParent) reachableAncestor[this.parents[v]] = reachableAncestor[v]; 53 | }; 54 | 55 | const reachableAncestor = new Array(vertices + 1); 56 | const treeOutDegree = new Array(vertices + 1).fill(0); 57 | dfs.parents[1] = -1; 58 | dfs.search(1); 59 | -------------------------------------------------------------------------------- /implementations/graphs/graphTraversal.mjs: -------------------------------------------------------------------------------- 1 | import { Graph } from "../../data-structures/Graph.mjs"; 2 | import BFS from "../../algorithms/graphs/BFS.mjs"; 3 | import DFS from "../../algorithms/graphs/DFS.mjs"; 4 | 5 | const vertices = 6; 6 | const g = new Graph(vertices, false); 7 | g.insertEdges([[1, 6],[1, 5],[1, 2],[2, 5],[2, 3],[3, 4],[4, 5]]); 8 | 9 | const bfs = new BFS(g); 10 | const dfs = new DFS(g); 11 | 12 | bfs.processEdge = function (x, y) { 13 | console.log(x + "->" + y); 14 | }; 15 | 16 | dfs.processEdge = function (x, y) { 17 | console.log(x + "->" + y); 18 | }; 19 | 20 | console.log("BFS edges"); 21 | bfs.search(1); 22 | 23 | console.log("\nDFS edges"); 24 | dfs.search(1); 25 | -------------------------------------------------------------------------------- /implementations/graphs/topologicalSort.mjs: -------------------------------------------------------------------------------- 1 | import { Graph } from "../../data-structures/Graph.mjs"; 2 | import DFS from "../../algorithms/graphs/DFS.mjs"; 3 | 4 | const vertices = 7; 5 | const g = new Graph(vertices, true); 6 | g.insertEdges([[1, 2],[1, 3],[2, 3],[2, 4],[3, 5],[5, 4],[3, 6],[6, 5],[1, 7],[7, 6]]); 7 | 8 | const dfs = new DFS(g); 9 | const toposort = []; 10 | 11 | dfs.processVertextLate = function (v) { 12 | toposort.unshift(v); 13 | }; 14 | 15 | dfs.processEdge = function (x, y) { 16 | if (this.discovered[y] === !this.processed[y]) { 17 | console.log("Loop exists"); 18 | this.finished = true; 19 | } 20 | }; 21 | 22 | dfs.parents[1] = -1; 23 | for (let i = 1; i < vertices; i++) { 24 | if (!dfs.discovered[i]) { 25 | dfs.search(i); 26 | } 27 | } 28 | console.log("Topological sort: " + toposort); 29 | -------------------------------------------------------------------------------- /implementations/search/binarySearchWithBoundaries.mjs: -------------------------------------------------------------------------------- 1 | import BS from "../../algorithms/search/BinarySearch.mjs"; 2 | 3 | let array = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 5]; 4 | let bs = new BS(array); 5 | 6 | const leftIndex = bs.getLeftBound(1); 7 | const rightIndex = bs.getRightBound(1); 8 | 9 | const element = 4; 10 | const index = new BS(array).getIndex(element); 11 | console.log(array); 12 | console.log(`array[${index}] = ${element}`); 13 | console.log(`Left index: ${leftIndex}, Right index: ${rightIndex}, Occurences: ${rightIndex - leftIndex}`); 14 | -------------------------------------------------------------------------------- /implementations/sort/sort.mjs: -------------------------------------------------------------------------------- 1 | import HeapSort from "../../algorithms/sorting/HeapSort.mjs"; 2 | import MergeSort from "../../algorithms/sorting/MergeSort.mjs"; 3 | import QuickSort from "../../algorithms/sorting/QuickSort.mjs"; 4 | 5 | // to build heap 6 | // let heap = new HeapSort(); 7 | // heap.insert(7)(9)(4)(3)(6)(7)(1)(5); 8 | // console.log(heap.array); 9 | 10 | const array = [7, 9, 4, 3, 6, 7, 1, 5]; 11 | 12 | const heap = new HeapSort([...array]); 13 | heap.sort(); 14 | console.log(heap.array); 15 | 16 | const merge = new MergeSort([...array]); 17 | console.log(merge.sort()); 18 | 19 | const quick = new QuickSort([...array]); 20 | quick.sort(); 21 | console.log(quick.array); 22 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [3.2.0] - 2021-08-05 10 | ### Added 11 | - CustomHeap to allow constructing a heap with a custom comparator callback. 12 | 13 | ## [3.1.1] - 2021-06-20 14 | 15 | ### Fixed 16 | - index.d.ts 17 | 18 | ## [3.1.0] - 2021-06-15 19 | 20 | ### Added 21 | - typescript. 22 | 23 | ## [3.0.1] - 2021-03-28 24 | 25 | ### Fixed 26 | - Readme 27 | 28 | ## [3.0.0] - 2020-01-17 29 | 30 | ### Changed 31 | - simplified heap nodes. preserves numbers and strings, and use object literal for key:value. 32 | - `.heapify` static function now heapify the input list as well as returning a heap insatnce. 33 | 34 | ### Added 35 | - `.fix()` to fix positions of nodes in the heap. 36 | - `.isValid` to validate heap nodes are in right positions. 37 | - `.isHeapified` static function to valida if a given list is heapified. 38 | 39 | ### Fixed 40 | - jsdoc 41 | - README 42 | 43 | ## [2.0.0] - 2020-04-06 44 | ### Changed 45 | - remove none-standard method `.serialize()`. 46 | 47 | ### Fixed 48 | - return inserted node in Min/Max Heap. 49 | - README 50 | - jsdoc 51 | 52 | ## [1.2.0] - 2020-03-07 53 | ### Added 54 | - `.leaf()` to get the max node in a MinHeap or the min node in a MaxHeap. 55 | 56 | ## [1.1.2] - 2020-03-06 57 | ### Fixed 58 | - params naming. 59 | 60 | ## [1.1.1] - 2019-12-24 61 | ### Fixed 62 | - add a table of content to readme 63 | 64 | ## [1.1.0] - 2019-12-16 65 | ### Added 66 | `.serialize()` to convert a heap to a list of serialized nodes. 67 | 68 | ### Fixed 69 | - improve README. 70 | 71 | ## [1.0.1] - 2019-12-16 72 | ### Fixed 73 | - Readme & Description. 74 | 75 | ## [1.0.0] - 2019-12-15 76 | ### Added 77 | - initial release 78 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Eyas Ranjous 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/README.md: -------------------------------------------------------------------------------- 1 | # @datastructures-js/heap 2 | [![build:?](https://travis-ci.org/datastructures-js/heap.svg?branch=master)](https://travis-ci.org/datastructures-js/heap) 3 | [![npm](https://img.shields.io/npm/v/@datastructures-js/heap.svg)](https://www.npmjs.com/package/@datastructures-js/heap) 4 | [![npm](https://img.shields.io/npm/dm/@datastructures-js/heap.svg)](https://www.npmjs.com/package/@datastructures-js/heap) [![npm](https://img.shields.io/badge/node-%3E=%206.0-blue.svg)](https://www.npmjs.com/package/@datastructures-js/heap) 5 | 6 | a javascript implementation for Heap data structure & Heap Sort algorithm. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 20 |
Min HeapMax Heap
14 | Min Heap 15 | 17 | Max Heap 18 |
21 | 22 | # Contents 23 | * [Install](#install) 24 | * [require](#require) 25 | * [import](#import) 26 | * [API](#api) 27 | * [constructor](#constructor) 28 | * [.insert(key[, value])](#insertkey-value) 29 | * [.extractRoot()](#extractroot) 30 | * [.root()](#root) 31 | * [.leaf()](#leaf) 32 | * [.size()](#size) 33 | * [.clone()](#clone) 34 | * [.isValid()](#isvalid) 35 | * [.fix()](#fix) 36 | * [.sort()](#sort) 37 | * [.clear()](#clear) 38 | * [Heap.heapify(list)](#heapheapifylist) 39 | * [Heap.isHeapified(list)](#heapisHeapifiedlist) 40 | * [Build](#build) 41 | * [License](#license) 42 | 43 | ## install 44 | ```sh 45 | npm install --save @datastructures-js/heap 46 | ``` 47 | 48 | ### require 49 | ```js 50 | const { MinHeap, MaxHeap, CustomHeap } = require('@datastructures-js/heap'); 51 | ``` 52 | 53 | ### import 54 | ```js 55 | import { MinHeap, MaxHeap, CustomHeap, HeapNode } from '@datastructures-js/heap'; 56 | // HeapNode is the key/value interface for MinHeap/MaxHeap 57 | ``` 58 | 59 | ## API 60 | 61 | ### constructor 62 | creates an empty heap. use **CustomHeap** when you need advanced comparison logic between heap nodes. For primitive comparisons, use MinHeap/MaxHeap. 63 | 64 | ##### JS 65 | ```js 66 | const minHeap = new MinHeap(); 67 | 68 | const maxHeap = new MaxHeap(); 69 | 70 | // comparator receievs the parent (a) and child (b) in each comparison 71 | // and should return a number, if bigger than 0, it will swap nodes. 72 | const customMinHeap = new CustomHeap((a, b) => a.count - b.count); 73 | 74 | const customMaxHeap = new CustomHeap((a, b) => a.name < b.name ? 1 : -1); 75 | ``` 76 | 77 | ##### TS 78 | ```js 79 | const minHeap = new MinHeap(); 80 | 81 | const maxHeap = new MaxHeap(); 82 | 83 | // comparator receievs the parent (a) and child (b) in each comparison 84 | // and should return a number, if bigger than 0, it will swap nodes. 85 | const customMinHeap = new CustomHeap<{ count: number }>( 86 | (a, b) => a.count - b.count 87 | ); 88 | 89 | const customMaxHeap = new CustomHeap<{ name: string }>( 90 | (a, b) => a.name < b.name ? 1 : -1 91 | ); 92 | ``` 93 | 94 | ### .insert(key[, value]) 95 | insert a node into the heap. If value is provided (anything except undefined), the node is stored as `{key: ..., value: ...}` otherwise, the node is the key (number or string). For CustomHeap, anything can be inserted as a comparator is provided to compare nodes. 96 | 97 | ##### MinHeap/MaxHeap 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 110 | 111 | 112 | 113 |
paramsreturnruntime
106 | key: T (number | string) 107 |
108 | value: U (any) 109 |
MinHeap<T, U> | MaxHeap<T, U>O(log(n))
114 | 115 | ```js 116 | minHeap 117 | .insert(50) 118 | .insert(80) 119 | .insert(30, 'something') 120 | .insert(90) 121 | .insert(60, null) 122 | .insert(40) 123 | .insert(20, { name: 'test' }); 124 | 125 | maxHeap 126 | .insert('m') 127 | .insert('x') 128 | .insert('f', 'something') 129 | .insert('b') 130 | .insert('z', null) 131 | .insert('k') 132 | .insert('c', { name: 'test' }); 133 | ``` 134 | 135 | ##### CustomHeap 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 146 | 147 | 148 | 149 |
paramsreturnruntime
144 | key: T 145 | CustomHeap<T>O(log(n))
150 | 151 | ```js 152 | customMaxHeap 153 | .insert({ name: 'm' }) 154 | .insert({ name: 'x' }) 155 | .insert({ name: 'f' }) 156 | .insert({ name: 'b' }) 157 | .insert({ name: 'z' }) 158 | .insert({ name: 'k' }) 159 | .insert({ name: 'c' }); 160 | ``` 161 | 162 | ### .extractRoot() 163 | removes and returns the root node in the heap. 164 | 165 | ##### MinHeap/MaxHeap 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 |
returnruntime
number | string | HeapNodeO(log(n))
176 | 177 | ```js 178 | console.log(minHeap.extractRoot()); // { key: 20, value: { name: 'test' } } 179 | console.log(minHeap.extractRoot()); // { key: 30, value: 'something' } 180 | console.log(minHeap.extractRoot()); // 40 181 | 182 | console.log(maxHeap.extractRoot()); // { key: 'z', value: null } 183 | console.log(maxHeap.extractRoot()); // 'x' 184 | console.log(maxHeap.extractRoot()); // 'm' 185 | ``` 186 | 187 | ##### CustomHeap 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 |
returnruntime
TO(log(n))
198 | 199 | ```js 200 | console.log(customMaxHeap.extractRoot()); // { name: 'z' } 201 | console.log(customMaxHeap.extractRoot()); // { name: 'x' } 202 | console.log(customMaxHeap.extractRoot()); // { name: 'm' } 203 | ``` 204 | 205 | ### .root() 206 | returns the root node without removing it. 207 | 208 | ##### MinHeap/MaxHeap 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 |
returnruntime
number | string | HeapNodeO(1)
219 | 220 | ```js 221 | console.log(minHeap.root()); // 50 222 | 223 | console.log(maxHeap.root()); // 'k' 224 | ``` 225 | 226 | ##### CustomHeap 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 |
returnruntime
TO(1)
237 | 238 | ```js 239 | console.log(customMaxHeap.root()); // { name: 'k' } 240 | ``` 241 | 242 | ### .leaf() 243 | returns a node with max key in MinHeap, or with min key in MaxHeap. 244 | 245 | ##### MinHeap/MaxHeap 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 |
returnruntime
number | string | HeapNodeO(1)
256 | 257 | ```js 258 | console.log(minHeap.leaf()); // 90 259 | 260 | console.log(maxHeap.leaf()); // 'b' 261 | ``` 262 | 263 | ##### CustomHeap 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 |
returnruntime
TO(1)
274 | 275 | ```js 276 | console.log(customMaxHeap.leaf()); // { name: 'b' } 277 | ``` 278 | 279 | ### .size() 280 | returns the number of nodes in the heap. 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 |
returnruntime
numberO(1)
292 | 293 | ```js 294 | console.log(minHeap.size()); // 4 295 | console.log(maxHeap.size()); // 4 296 | console.log(customMaxHeap.size()); // 4 297 | ``` 298 | 299 | ### .clone() 300 | creates a shallow copy of the heap. 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 |
returnruntime
MinHeap | MaxHeap | CustomHeapO(n)
312 | 313 | ```js 314 | const minHeapClone = minHeap.clone(); 315 | minHeapClone.extractRoot(); 316 | console.log(minHeapClone.root()); // 60 317 | console.log(minHeap.root()); // 50 318 | 319 | const maxHeapClone = maxHeap.clone(); 320 | maxHeapClone.extractRoot(); 321 | console.log(maxHeapClone.root()); // { key: 'f', value: 'something' } 322 | console.log(maxHeap.root()); // 'k' 323 | 324 | const customMaxHeapClone = customMaxHeap.clone(); 325 | customMaxHeap.extractRoot(); 326 | console.log(customMaxHeap.root()); // { name: 'f' } 327 | console.log(customMaxHeapClone.root()); // { name: 'k' } 328 | ``` 329 | 330 | ### .isValid() 331 | checks if the heap is valid. 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 |
returnruntime
booleanO(log(n))
343 | 344 | ```js 345 | console.log(minHeap.isValid()); // true 346 | 347 | console.log(maxHeap.isValid()); // true 348 | 349 | console.log(customMaxHeap.isValid()); // true 350 | ``` 351 | 352 | ### .fix() 353 | fixes a heap by making the necessary changes in node positions. 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 |
returnruntime
MinHeap | MaxHeap | CustomHeapO(log(n))
365 | 366 | ```js 367 | console.log(minHeap.fix().isValid()); // true 368 | 369 | console.log(maxHeap.fix().isValid()); // true 370 | 371 | console.log(customMaxHeap.fix().isValid()); // true 372 | ``` 373 | 374 | ### .sort() 375 | implements Heap Sort and sorts a Max Heap in ascending order or a Min Heap in descending order. 376 | 377 | ##### MinHeap/MaxHeap 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 |
returnruntime
array<number|string|HeapNode>O(n*log(n))
389 | 390 | *note: calling .sort() directly on a heap will mutate its nodes location. To avoid that, you might either sort a shallow copy. You can also use use .fix() to fix the mutated heap positions* 391 | 392 | ```js 393 | console.log(maxHeap.clone().sort()); // sorting a copy of the heap 394 | /* 395 | [ 396 | 'b', 397 | { key: 'c', value: { name: 'test' } }, 398 | { key: 'f', value: 'something' }, 399 | 'k' 400 | ] 401 | */ 402 | console.log(maxHeap.root()); // 'k' 403 | 404 | console.log(minHeap.sort()); // will mutate the heap 405 | /* 406 | [ 90, 80, { key: 60, value: null }, 50 ] 407 | */ 408 | console.log(minHeap.isValid()); // false 409 | minHeap.fix(); // fix it 410 | console.log(minHeap.isValid()); // true 411 | ``` 412 | 413 | To sort a list of elements directtly using Heap Sort, it can be done like: 414 | 415 | ```js 416 | const ascSorted = MaxHeap.heapify([3, 7, 2, 10, 4, 9, 8, 5, 1, 6]).sort(); 417 | // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 418 | 419 | const descSorted = MinHeap.heapify([3, 7, 2, 10, 4, 9, 8, 5, 1, 6]).sort(); 420 | // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 421 | ``` 422 | 423 | ##### CustomHeap 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 |
returnruntime
array<T>O(n*log(n))
434 | 435 | ```js 436 | // sorting custom max heap in ascending order 437 | console.log(customMaxHeap.clone().sort()); 438 | /* 439 | [ 440 | { name: 'b' }, 441 | { name: 'c' }, 442 | { name: 'f' }, 443 | { name: 'k' }, 444 | { name: 'm' }, 445 | { name: 'x' }, 446 | { name: 'z' } 447 | ] 448 | */ 449 | ``` 450 | 451 | ### .clear() 452 | clears the nodes in the heap. 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 |
runtime
O(1)
462 | 463 | ```js 464 | minHeap.clear(); 465 | maxHeap.clear(); 466 | 467 | console.log(minHeap.size()); // 0 468 | console.log(minHeap.root()); // null 469 | 470 | console.log(customMaxHeap.size()); // 0 471 | console.log(customMaxHeap.root()); // null 472 | ``` 473 | 474 | ### Heap.heapify(list) 475 | Heapifies an existing list. It returns a heap instance as well as changing the list positions properly. 476 | 477 | ##### MinHeap/MaxHeap 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 |
paramsreturnruntime
list: array<number | string | HeapNode>MinHeap | MaxHeapO(n)
490 | 491 | ###### JS 492 | ```js 493 | const numList = [50, 80, 30, 90, 60, 40, 20]; 494 | MinHeap.heapify(numList); 495 | console.log(numList); // [20, 60, 30, 90, 80, 50, 40] 496 | 497 | const strList = ['m', 'x', 'f', 'b', 'z', 'k', 'c']; 498 | const maxHeap = MaxHeap.heapify(strList); 499 | console.log(strList); // ['z', 'x', 'k', 'b', 'm', 'f', 'c'] 500 | console.log(maxHeap.isValid()); // true 501 | 502 | const objList = [ 503 | { key: 50, value: 't1' }, 504 | { key: 80, value: 't2' }, 505 | { key: 30, value: 't3' }, 506 | { key: 90, value: 't4' }, 507 | { key: 60, value: 't5' }, 508 | { key: 40, value: 't6' }, 509 | { key: 20, value: 't7' } 510 | ]; 511 | MinHeap.heapify(objList); 512 | console.log(objList); 513 | /* 514 | [ 515 | { key: 20, value: 't7' }, 516 | { key: 60, value: 't5' }, 517 | { key: 30, value: 't3' }, 518 | { key: 90, value: 't4' }, 519 | { key: 80, value: 't2' }, 520 | { key: 50, value: 't1' }, 521 | { key: 40, value: 't6' } 522 | ] 523 | */ 524 | ``` 525 | 526 | ###### TS 527 | ```js 528 | const numList = [50, 80, 30, 90, 60, 40, 20]; 529 | MinHeap.heapify(numList); 530 | console.log(numList); // [20, 60, 30, 90, 80, 50, 40] 531 | 532 | const objList = [ 533 | { key: 50, value: 't1' }, 534 | { key: 80, value: 't2' }, 535 | { key: 30, value: 't3' }, 536 | { key: 90, value: 't4' }, 537 | { key: 60, value: 't5' }, 538 | { key: 40, value: 't6' }, 539 | { key: 20, value: 't7' } 540 | ]; 541 | MinHeap.heapify(objList); 542 | console.log(objList); 543 | /* 544 | [ 545 | { key: 20, value: 't7' }, 546 | { key: 60, value: 't5' }, 547 | { key: 30, value: 't3' }, 548 | { key: 90, value: 't4' }, 549 | { key: 80, value: 't2' }, 550 | { key: 50, value: 't1' }, 551 | { key: 40, value: 't6' } 552 | ] 553 | */ 554 | ``` 555 | 556 | ##### CustomHeap 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 569 | 570 | 571 | 572 |
paramsreturnruntime
565 | list: array<T> 566 |
567 | comparator: (a: T, b: T) => number 568 |
CustomHeap<T>O(n)
573 | 574 | ```js 575 | const counts = [ 576 | { count: 50 }, 577 | { count: 80 }, 578 | { count: 30 }, 579 | { count: 90 }, 580 | { count: 60 }, 581 | { count: 40 }, 582 | { count: 20 } 583 | ]; 584 | CustomHeap.heapify<{ count: number }>(counts, (a, b) => a.count - b.count); 585 | 586 | console.log(counts); // minHeap list 587 | /* 588 | [ 589 | { count: 20 }, 590 | { count: 60 }, 591 | { count: 30 }, 592 | { count: 90 }, 593 | { count: 80 }, 594 | { count: 50 }, 595 | { count: 40 } 596 | ] 597 | */ 598 | ``` 599 | 600 | ### Heap.isHeapified(list) 601 | Checks if a given list is heapified. 602 | 603 | ##### MinHeap/MaxHeap 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 614 | 615 | 616 | 617 |
paramsreturnruntime
612 | list: array<number | string | HeapNode> 613 | booleanO(log(n))
618 | 619 | ###### JS 620 | ```js 621 | MinHeap.isHeapified([50, 80, 30, 90, 60, 40, 20]); // false 622 | 623 | MinHeap.isHeapified([20, 60, 30, 90, 80, 50, 40]); // true 624 | 625 | MaxHeap.isHeapified(['m', 'x', 'f', 'b', 'z', 'k', 'c']); // false 626 | 627 | MaxHeap.isHeapified(['z', 'x', 'k', 'b', 'm', 'f', 'c']); // true 628 | ``` 629 | 630 | ###### TS 631 | ```js 632 | MinHeap.isHeapified([20, 60, 30, 90, 80, 50, 40]); // true 633 | 634 | MaxHeap.isHeapified(['z', 'x', 'k', 'b', 'm', 'f', 'c']); // true 635 | ``` 636 | 637 | ##### CustomHeap 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 651 | 652 | 653 | 654 |
paramsreturnruntime
647 | list: array<T> 648 |
649 | comparator: (a: T, b: T) => number 650 |
booleanO(log(n))
655 | 656 | ```js 657 | const counts = [ 658 | { count: 20 }, 659 | { count: 60 }, 660 | { count: 30 }, 661 | { count: 90 }, 662 | { count: 80 }, 663 | { count: 50 }, 664 | { count: 40 } 665 | ]; 666 | 667 | console.log(CustomHeap.isHeapified<{ count: number }>(counts, (a, b) => a.count - b.count)); // true 668 | ``` 669 | 670 | ## Build 671 | 672 | ``` 673 | grunt build 674 | ``` 675 | 676 | ## License 677 | The MIT License. Full License is [here](https://github.com/datastructures-js/heap/blob/master/LICENSE) 678 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/index.d.ts: -------------------------------------------------------------------------------- 1 | import { HeapNode } from './src/heap'; 2 | import { MinHeap } from './src/minHeap'; 3 | import { MaxHeap } from './src/maxHeap'; 4 | import { CustomHeap } from './src/customHeap'; 5 | 6 | export { HeapNode } 7 | export { MinHeap } 8 | export { MaxHeap } 9 | export { CustomHeap } 10 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/index.js: -------------------------------------------------------------------------------- 1 | const { MinHeap } = require('./src/minHeap'); 2 | const { MaxHeap } = require('./src/maxHeap'); 3 | const { CustomHeap } = require('./src/customHeap'); 4 | 5 | exports.MinHeap = MinHeap; 6 | exports.MaxHeap = MaxHeap; 7 | exports.CustomHeap = CustomHeap; 8 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "@datastructures-js/heap@^3.2.0", 3 | "_id": "@datastructures-js/heap@3.2.0", 4 | "_inBundle": false, 5 | "_integrity": "sha512-FcU5ZAyb+VIOZz1HABsJUsbJi2ZyUDO7aoe97hq4d3tK3z8nMgwdxf5bO0gafR0ExFi18YTspntqHLzt4XOgnA==", 6 | "_location": "/@datastructures-js/heap", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "range", 10 | "registry": true, 11 | "raw": "@datastructures-js/heap@^3.2.0", 12 | "name": "@datastructures-js/heap", 13 | "escapedName": "@datastructures-js%2fheap", 14 | "scope": "@datastructures-js", 15 | "rawSpec": "^3.2.0", 16 | "saveSpec": null, 17 | "fetchSpec": "^3.2.0" 18 | }, 19 | "_requiredBy": [ 20 | "/@datastructures-js/priority-queue" 21 | ], 22 | "_resolved": "https://registry.npmjs.org/@datastructures-js/heap/-/heap-3.2.0.tgz", 23 | "_shasum": "d8fcdbf58c462c8a3f0fdfd9c6a57ca11505321e", 24 | "_spec": "@datastructures-js/heap@^3.2.0", 25 | "_where": "/Users/sadanandpaim/Documents/sadanand/projects/DSA/node_modules/@datastructures-js/priority-queue", 26 | "author": { 27 | "name": "Eyas Ranjous", 28 | "email": "eyas-ranjous@gmail.com" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/datastructures-js/heap/issues" 32 | }, 33 | "bundleDependencies": false, 34 | "deprecated": false, 35 | "description": "Min/Max Heap & Heap Sort implementation in javascript", 36 | "devDependencies": { 37 | "chai": "^4.2.0", 38 | "eslint": "^6.7.2", 39 | "eslint-config-airbnb-base": "^14.0.0", 40 | "eslint-plugin-import": "^2.19.1", 41 | "grunt": "^1.0.4", 42 | "grunt-eslint": "^22.0.0", 43 | "grunt-mocha-istanbul": "^5.0.2", 44 | "grunt-mocha-test": "^0.13.3", 45 | "istanbul": "^0.4.5", 46 | "mocha": "^6.2.2" 47 | }, 48 | "homepage": "https://github.com/datastructures-js/heap#readme", 49 | "keywords": [ 50 | "heap", 51 | "min heap", 52 | "min heap data structure", 53 | "max heap", 54 | "max heap data structure", 55 | "heap js", 56 | "heap data structure", 57 | "heap es6", 58 | "heap sort", 59 | "heapify" 60 | ], 61 | "license": "MIT", 62 | "main": "index.js", 63 | "name": "@datastructures-js/heap", 64 | "repository": { 65 | "type": "git", 66 | "url": "git+https://github.com/datastructures-js/heap.git" 67 | }, 68 | "scripts": { 69 | "test": "grunt test" 70 | }, 71 | "version": "3.2.0" 72 | } 73 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/customHeap.d.ts: -------------------------------------------------------------------------------- 1 | import { Heap } from './heap'; 2 | 3 | export class CustomHeap extends Heap { 4 | constructor( 5 | comparator: (a: T, b: T) => number, 6 | elements?: T[], 7 | leaf?: T 8 | ); 9 | 10 | static heapify( 11 | list: T[], 12 | comparator: (a: T, b: T) => number 13 | ): CustomHeap; 14 | 15 | static isHeapified( 16 | list: T[], 17 | comparator: (a: T, b: T) => number 18 | ): boolean; 19 | } 20 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/customHeap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license MIT 3 | * @copyright 2020 Eyas Ranjous 4 | */ 5 | 6 | const { Heap } = require('./heap'); 7 | 8 | /** 9 | * @class CustomHeap 10 | * @extends Heap 11 | */ 12 | class CustomHeap extends Heap { 13 | constructor(comparator, nodes, leaf) { 14 | if (typeof comparator !== 'function') { 15 | throw new Error('CustomHeap expects a comparator function'); 16 | } 17 | super(nodes, leaf); 18 | this._comparator = comparator; 19 | } 20 | 21 | /** 22 | * Compares parent & child nodes 23 | * and returns true if they are in right positions 24 | * 25 | * @private 26 | * @param {object|number|string} parent 27 | * @param {object|number|string} child 28 | * @returns {number} 29 | */ 30 | _compare(parentNode, childNode) { 31 | return this._comparator(parentNode, childNode) <= 0; 32 | } 33 | 34 | /** 35 | * Returns child's index of two children before an index 36 | * @private 37 | * @param {number} index 38 | * @param {number} leftChildIndex 39 | * @param {number} rightChildIndex 40 | * @returns {number} 41 | */ 42 | _compareChildrenBefore(index, leftChildIndex, rightChildIndex) { 43 | const compare = this._comparator( 44 | this._nodes[rightChildIndex], 45 | this._nodes[leftChildIndex] 46 | ); 47 | 48 | if (compare <= 0 && rightChildIndex < index) { 49 | return rightChildIndex; 50 | } 51 | 52 | return leftChildIndex; 53 | } 54 | 55 | /** 56 | * Returns a shallow copy of the heap 57 | * @public 58 | * @returns {CustomHeap} 59 | */ 60 | clone() { 61 | return new CustomHeap( 62 | this._comparator, 63 | this._nodes.slice(), 64 | this._leaf 65 | ); 66 | } 67 | 68 | /** 69 | * Builds a custom heap from an array of items 70 | * @public 71 | * @static 72 | * @param {array} list 73 | * @param {function} comparator 74 | * @returns {CustomHeap} 75 | */ 76 | static heapify(list, comparator) { 77 | if (!Array.isArray(list)) { 78 | throw new Error('.heapify expects an array'); 79 | } 80 | 81 | if (typeof comparator !== 'function') { 82 | throw new Error('.heapify expects a comparator function'); 83 | } 84 | 85 | return new CustomHeap(comparator, list).fix(); 86 | } 87 | 88 | /** 89 | * Checks if a list of items is a valid custom heap 90 | * @public 91 | * @static 92 | * @param {array} list 93 | * @param {function} comparator 94 | * @returns {boolean} 95 | */ 96 | static isHeapified(list, comparator) { 97 | if (!Array.isArray(list)) { 98 | throw new Error('.heapify expects an array'); 99 | } 100 | 101 | if (typeof comparator !== 'function') { 102 | throw new Error('.isHeapified expects a comparator function'); 103 | } 104 | 105 | return new CustomHeap(comparator, list).isValid(); 106 | } 107 | } 108 | 109 | exports.CustomHeap = CustomHeap; 110 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/heap.d.ts: -------------------------------------------------------------------------------- 1 | export interface HeapNode { 2 | key: T; 3 | value: U; 4 | } 5 | 6 | export abstract class Heap { 7 | constructor(elements?: (HeapNode | T)[], leaf?: (HeapNode | T)); 8 | extractRoot(): HeapNode | T; 9 | insert(key: T, value?: U): Heap; 10 | sort(): (HeapNode | T)[]; 11 | fix(): void; 12 | isValid(): boolean; 13 | root(): HeapNode | T; 14 | leaf(): HeapNode | T; 15 | size(): number; 16 | isEmpty(): boolean; 17 | clear(): void; 18 | clone(): Heap; 19 | } 20 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/heap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license MIT 3 | * @copyright 2020 Eyas Ranjous 4 | * 5 | * @class 6 | * @abstract 7 | */ 8 | class Heap { 9 | /** 10 | * Creates a heap instance 11 | * @param {array} nodes 12 | * @param {string|number|object} [leaf] 13 | * @returns {number} 14 | */ 15 | constructor(nodes, leaf) { 16 | this._nodes = Array.isArray(nodes) ? nodes : []; 17 | this._leaf = leaf || null; 18 | } 19 | 20 | /** 21 | * Checks if a parent has a left child 22 | * @private 23 | * @param {number} parentIndex 24 | * @returns {boolean} 25 | */ 26 | _hasLeftChild(parentIndex) { 27 | const leftChildIndex = (parentIndex * 2) + 1; 28 | return leftChildIndex < this.size(); 29 | } 30 | 31 | /** 32 | * Checks if a parent has a right child 33 | * @private 34 | * @param {number} parentIndex 35 | * @returns {boolean} 36 | */ 37 | _hasRightChild(parentIndex) { 38 | const rightChildIndex = (parentIndex * 2) + 2; 39 | return rightChildIndex < this.size(); 40 | } 41 | 42 | /** 43 | * Returns heap node's key 44 | * @private 45 | * @param {object|number|string} node 46 | * @returns {number|string} 47 | */ 48 | _getKey(node) { 49 | if (typeof node === 'object') return node.key; 50 | return node; 51 | } 52 | 53 | /** 54 | * Swaps two nodes in the heap 55 | * @private 56 | * @param {number} i 57 | * @param {number} j 58 | */ 59 | _swap(i, j) { 60 | const temp = this._nodes[i]; 61 | this._nodes[i] = this._nodes[j]; 62 | this._nodes[j] = temp; 63 | } 64 | 65 | /** 66 | * Compares parent & child nodes 67 | * and returns true if they are in right positions 68 | * 69 | * @private 70 | * @param {object|number|string} parent 71 | * @param {object|number|string} child 72 | * @returns {boolean} 73 | */ 74 | _compare(parentNode, childNode) { 75 | return this._compareKeys( 76 | this._getKey(parentNode), 77 | this._getKey(childNode) 78 | ); 79 | } 80 | 81 | /** 82 | * Checks if parent and child nodes should be swapped 83 | * @private 84 | * @param {number} parentIndex 85 | * @param {number} childIndex 86 | * @returns {boolean} 87 | */ 88 | _shouldSwap(parentIndex, childIndex) { 89 | if (parentIndex < 0 || parentIndex >= this.size()) return false; 90 | if (childIndex < 0 || childIndex >= this.size()) return false; 91 | 92 | return !this._compare( 93 | this._nodes[parentIndex], 94 | this._nodes[childIndex] 95 | ); 96 | } 97 | 98 | /** 99 | * Bubbles a node from a starting index up in the heap 100 | * @param {number} startingIndex 101 | * @public 102 | */ 103 | heapifyUp(startingIndex) { 104 | let childIndex = startingIndex; 105 | let parentIndex = Math.floor((childIndex - 1) / 2); 106 | 107 | while (this._shouldSwap(parentIndex, childIndex)) { 108 | this._swap(parentIndex, childIndex); 109 | childIndex = parentIndex; 110 | parentIndex = Math.floor((childIndex - 1) / 2); 111 | } 112 | } 113 | 114 | /** 115 | * Compares left and right & children of a parent 116 | * @private 117 | * @param {number} parentIndex 118 | * @returns {number} - a child's index 119 | */ 120 | _compareChildrenOf(parentIndex) { 121 | if ( 122 | !this._hasLeftChild(parentIndex) 123 | && !this._hasRightChild(parentIndex) 124 | ) { 125 | return -1; 126 | } 127 | 128 | const leftChildIndex = (parentIndex * 2) + 1; 129 | const rightChildIndex = (parentIndex * 2) + 2; 130 | 131 | if (!this._hasLeftChild(parentIndex)) { 132 | return rightChildIndex; 133 | } 134 | 135 | if (!this._hasRightChild(parentIndex)) { 136 | return leftChildIndex; 137 | } 138 | 139 | const isLeft = this._compare( 140 | this._nodes[leftChildIndex], 141 | this._nodes[rightChildIndex] 142 | ); 143 | 144 | return isLeft ? leftChildIndex : rightChildIndex; 145 | } 146 | 147 | /** 148 | * Pushes a node from a starting index down in the heap 149 | * @private 150 | */ 151 | _heapifyDown(startingIndex) { 152 | let parentIndex = startingIndex; 153 | let childIndex = this._compareChildrenOf(parentIndex); 154 | 155 | while (this._shouldSwap(parentIndex, childIndex)) { 156 | this._swap(parentIndex, childIndex); 157 | parentIndex = childIndex; 158 | childIndex = this._compareChildrenOf(parentIndex); 159 | } 160 | } 161 | 162 | /** 163 | * Removes and returns the root node in the heap 164 | * @public 165 | * @returns {object} 166 | */ 167 | extractRoot() { 168 | if (this.isEmpty()) return null; 169 | 170 | const root = this.root(); 171 | this._nodes[0] = this._nodes[this.size() - 1]; 172 | this._nodes.pop(); 173 | this._heapifyDown(0); 174 | 175 | if (root === this._leaf) { 176 | this._leaf = this.root(); 177 | } 178 | 179 | return root; 180 | } 181 | 182 | /** 183 | * Pushes a node with down in the heap before an index 184 | * @private 185 | * @param {number} index 186 | */ 187 | _heapifyDownUntil(index) { 188 | let parentIndex = 0; 189 | let leftChildIndex = 1; 190 | let rightChildIndex = 2; 191 | let childIndex; 192 | 193 | while (leftChildIndex < index) { 194 | childIndex = this._compareChildrenBefore( 195 | index, 196 | leftChildIndex, 197 | rightChildIndex 198 | ); 199 | 200 | if (this._shouldSwap(parentIndex, childIndex)) { 201 | this._swap(parentIndex, childIndex); 202 | } 203 | 204 | parentIndex = childIndex; 205 | leftChildIndex = (parentIndex * 2) + 1; 206 | rightChildIndex = (parentIndex * 2) + 2; 207 | } 208 | } 209 | 210 | /** 211 | * Returns a shallow copy of the heap 212 | * @protected 213 | * @param {class} HeapType 214 | * @returns {Heap} 215 | */ 216 | _clone(HeapType) { 217 | return new HeapType(this._nodes.slice(), this._leaf); 218 | } 219 | 220 | /** 221 | * Sorts the heap by swapping root with all nodes and fixing positions 222 | * @public 223 | * @returns {array} the sorted nodes 224 | */ 225 | sort() { 226 | for (let i = this.size() - 1; i > 0; i -= 1) { 227 | this._swap(0, i); 228 | this._heapifyDownUntil(i); 229 | } 230 | 231 | return this._nodes; 232 | } 233 | 234 | /** 235 | * Inserts a node in the right position into the heap 236 | * @public 237 | * @param {number|string} key 238 | * @param {any} [value] 239 | * @returns {Heap} 240 | */ 241 | insert(key, value) { 242 | const newNode = value !== undefined ? { key, value } : key; 243 | this._nodes.push(newNode); 244 | this.heapifyUp(this.size() - 1); 245 | if (this._leaf === null || !this._compare(newNode, this._leaf)) { 246 | this._leaf = newNode; 247 | } 248 | return this; 249 | } 250 | 251 | /** 252 | * Fixes all positions of the nodes in the heap 253 | * @public 254 | * @returns {Heap} 255 | */ 256 | fix() { 257 | for (let i = 0; i < this.size(); i += 1) { 258 | this.heapifyUp(i); 259 | } 260 | return this; 261 | } 262 | 263 | /** 264 | * Verifies that the heap is valid 265 | * @public 266 | * @returns {boolean} 267 | */ 268 | isValid() { 269 | const isValidRecursive = (parentIndex) => { 270 | let isValidLeft = true; 271 | let isValidRight = true; 272 | 273 | if (this._hasLeftChild(parentIndex)) { 274 | const leftChildIndex = (parentIndex * 2) + 1; 275 | isValidLeft = this._compare( 276 | this._nodes[parentIndex], 277 | this._nodes[leftChildIndex] 278 | ); 279 | 280 | if (!isValidLeft) { 281 | return false; 282 | } 283 | 284 | isValidLeft = isValidRecursive(leftChildIndex); 285 | } 286 | 287 | if (this._hasRightChild(parentIndex)) { 288 | const rightChildIndex = (parentIndex * 2) + 2; 289 | isValidRight = this._compare( 290 | this._nodes[parentIndex], 291 | this._nodes[rightChildIndex] 292 | ); 293 | 294 | if (!isValidRight) { 295 | return false; 296 | } 297 | 298 | isValidRight = isValidRecursive(rightChildIndex); 299 | } 300 | 301 | return isValidLeft && isValidRight; 302 | }; 303 | 304 | return isValidRecursive(0); 305 | } 306 | 307 | /** 308 | * Returns the root node in the heap 309 | * @public 310 | * @returns {object|number|string|null} 311 | */ 312 | root() { 313 | if (this.isEmpty()) return null; 314 | return this._nodes[0]; 315 | } 316 | 317 | /** 318 | * Returns a leaf node in the heap 319 | * @public 320 | * @returns {object|number|string|null} 321 | */ 322 | leaf() { 323 | return this._leaf; 324 | } 325 | 326 | /** 327 | * Returns the number of nodes in the heap 328 | * @public 329 | * @returns {number} 330 | */ 331 | size() { 332 | return this._nodes.length; 333 | } 334 | 335 | /** 336 | * Checks if the heap is empty 337 | * @public 338 | * @returns {boolean} 339 | */ 340 | isEmpty() { 341 | return this.size() === 0; 342 | } 343 | 344 | /** 345 | * Clears the heap 346 | * @public 347 | */ 348 | clear() { 349 | this._nodes = []; 350 | this._leaf = null; 351 | } 352 | 353 | /** 354 | * Convert a list of items into a heap 355 | * @protected 356 | * @static 357 | * @param {array} array 358 | * @param {class} HeapType 359 | * @returns {Heap} 360 | */ 361 | static _heapify(list, HeapType) { 362 | if (!Array.isArray(list)) { 363 | throw new Error('.heapify expects an array'); 364 | } 365 | 366 | return new HeapType(list).fix(); 367 | } 368 | 369 | /** 370 | * Checks if a list of items is a valid heap 371 | * @protected 372 | * @static 373 | * @param {array} array 374 | * @param {class} HeapType 375 | * @returns {boolean} 376 | */ 377 | static _isHeapified(list, HeapType) { 378 | return new HeapType(list).isValid(); 379 | } 380 | } 381 | 382 | exports.Heap = Heap; 383 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/maxHeap.d.ts: -------------------------------------------------------------------------------- 1 | import { HeapNode, Heap } from './heap'; 2 | 3 | export class MaxHeap extends Heap { 4 | clone(): MaxHeap; 5 | static heapify(list: (HeapNode | T)[]): MaxHeap; 6 | static isHeapified(list: (HeapNode | T)[]): boolean; 7 | } 8 | 9 | export { HeapNode }; 10 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/maxHeap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license MIT 3 | * @copyright 2020 Eyas Ranjous 4 | */ 5 | 6 | const { Heap } = require('./heap'); 7 | 8 | /** 9 | * @class MaxHeap 10 | * @extends Heap 11 | */ 12 | class MaxHeap extends Heap { 13 | /** 14 | * Checks two nodes are in relatively valid position 15 | * @private 16 | * @param {object} parent 17 | * @param {object} child 18 | * @returns {boolean} 19 | */ 20 | _compareKeys(parentKey, childKey) { 21 | return parentKey > childKey; 22 | } 23 | 24 | /** 25 | * Returns max child's index of two children before an index 26 | * @private 27 | * @param {number} index 28 | * @param {number} leftChildIndex 29 | * @param {number} rightChildIndex 30 | * @returns {number} 31 | */ 32 | _compareChildrenBefore(index, leftChildIndex, rightChildIndex) { 33 | const leftChildKey = this._getKey(this._nodes[leftChildIndex]); 34 | const rightChildKey = this._getKey(this._nodes[rightChildIndex]); 35 | 36 | if (rightChildKey > leftChildKey && rightChildIndex < index) { 37 | return rightChildIndex; 38 | } 39 | return leftChildIndex; 40 | } 41 | 42 | /** 43 | * Returns a shallow copy of the heap 44 | * @public 45 | * @returns {MaxHeap} 46 | */ 47 | clone() { 48 | return super._clone(MaxHeap); 49 | } 50 | 51 | /** 52 | * Builds a max heap from an array of items 53 | * @public 54 | * @static 55 | * @param {array} list 56 | * @returns {MaxHeap} 57 | */ 58 | static heapify(list) { 59 | return super._heapify(list, MaxHeap); 60 | } 61 | 62 | /** 63 | * Checks if a list of items is a valid max heap 64 | * @public 65 | * @static 66 | * @param {array} list 67 | * @returns {boolean} 68 | */ 69 | static isHeapified(list) { 70 | return super._isHeapified(list, MaxHeap); 71 | } 72 | } 73 | 74 | exports.MaxHeap = MaxHeap; 75 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/minHeap.d.ts: -------------------------------------------------------------------------------- 1 | import { HeapNode, Heap } from './heap'; 2 | 3 | export class MinHeap extends Heap { 4 | clone(): MinHeap; 5 | static heapify(list: (HeapNode | T)[]): MinHeap; 6 | static isHeapified(list: (HeapNode | T)[]): boolean; 7 | } 8 | 9 | export { HeapNode }; 10 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/heap/src/minHeap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license MIT 3 | * @copyright 2019 Eyas Ranjous 4 | */ 5 | 6 | const { Heap } = require('./heap'); 7 | 8 | /** 9 | * @class MinHeap 10 | * @extends Heap 11 | */ 12 | class MinHeap extends Heap { 13 | /** 14 | * Checks two nodes are in relatively valid position 15 | * @private 16 | * @param {object} parent 17 | * @param {object} child 18 | * @returns {boolean} 19 | */ 20 | _compareKeys(parentKey, childKey) { 21 | return parentKey < childKey; 22 | } 23 | 24 | /** 25 | * Returns min child's index of two children before an index 26 | * @protected 27 | * @param {number} index 28 | * @param {number} leftChildIndex 29 | * @param {number} rightChildIndex 30 | * @returns {number} 31 | */ 32 | _compareChildrenBefore(index, leftChildIndex, rightChildIndex) { 33 | const leftChildKey = this._getKey(this._nodes[leftChildIndex]); 34 | const rightChildKey = this._getKey(this._nodes[rightChildIndex]); 35 | 36 | if (rightChildKey < leftChildKey && rightChildIndex < index) { 37 | return rightChildIndex; 38 | } 39 | return leftChildIndex; 40 | } 41 | 42 | /** 43 | * Returns a shallow copy of the heap 44 | * @public 45 | * @returns {MinHeap} 46 | */ 47 | clone() { 48 | return super._clone(MinHeap); 49 | } 50 | 51 | /** 52 | * Builds a min heap from an array of items 53 | * @public 54 | * @static 55 | * @param {array} list 56 | * @returns {MinHeap} 57 | */ 58 | static heapify(list) { 59 | return super._heapify(list, MinHeap); 60 | } 61 | 62 | /** 63 | * Checks if a list of list is a valid min heap 64 | * @public 65 | * @static 66 | * @param {array} list 67 | * @returns {boolean} 68 | */ 69 | static isHeapified(list) { 70 | return super._isHeapified(list, MinHeap); 71 | } 72 | } 73 | 74 | exports.MinHeap = MinHeap; 75 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [5.3.0] - 2021-10-26 10 | ### Added 11 | - PriorityQueue as a type for queue with comparator. 12 | 13 | ## [5.2.0] - 2021-08-08 14 | ### Added 15 | - ability to create a priority queue with a comparator. 16 | 17 | ## [5.1.1] - 2021-06-20 18 | 19 | ### Fixed 20 | - index.d.ts 21 | 22 | ## [5.1.0] - 2021-06-17 23 | 24 | ### Added 25 | - typescript. 26 | 27 | ## [5.0.3] - 2021-04-27 28 | 29 | ### Fixed 30 | - README 31 | 32 | ## [5.0.2] - 2021-03-12 33 | 34 | ### Fixed 35 | - README 36 | 37 | ## [5.0.1] - 2021-02-23 38 | 39 | ### Fixed 40 | - README 41 | 42 | ## [5.0.0] - 2021-01-24 43 | ### Changed 44 | - upgrade heap to latest major version. 45 | - `.enqueue` can now be chanined. 46 | 47 | ### Added 48 | - a default priority callback that returns the element itself if no callback is provided. 49 | 50 | ### Fixed 51 | - cleaner error messages. 52 | - README 53 | - jsdoc 54 | 55 | ## [4.1.2] - 2020-09-22 56 | ### Fixed 57 | - Allow any number value for priority. 58 | 59 | ## [4.1.1] - 2020-05-03 60 | ### Fixed 61 | - README 62 | - package.json 63 | 64 | ## [4.1.0] - 2020-04-22 65 | ### Added 66 | - allow passing a priority callback in constructor. 67 | 68 | ## [4.0.0] - 2020-04-13 69 | ### Changed 70 | - split PriorityQueue into `MinPriorityQueue` & `MaxPriorityQueue` to enable working with different type of priorities. 71 | 72 | ## [3.0.1] - 2020-04-11 73 | ### Fixed 74 | - jsdoc 75 | 76 | ## [3.0.0] - 2020-04-09 77 | ### Changed 78 | - `.front()`, `.back()`, `.dequeue()`, `.toArray()` now returns the priority with the element. 79 | 80 | ### Fixed 81 | - README 82 | - jsdoc 83 | 84 | ## [2.0.0] - 2020-03-09 85 | ### Changed 86 | - use a Min Heap to store queue elements. 87 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Eyas Ranjous 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/README.md: -------------------------------------------------------------------------------- 1 | # @datastructures-js/priority-queue 2 | 3 | [![build:?](https://travis-ci.org/datastructures-js/priority-queue.svg?branch=master)](https://travis-ci.org/datastructures-js/priority-queue) 4 | [![npm](https://img.shields.io/npm/v/@datastructures-js/priority-queue.svg)](https://www.npmjs.com/package/@datastructures-js/priority-queue) 5 | [![npm](https://img.shields.io/npm/dm/@datastructures-js/priority-queue.svg)](https://www.npmjs.com/package/@datastructures-js/priority-queue) [![npm](https://img.shields.io/badge/node-%3E=%206.0-blue.svg)](https://www.npmjs.com/package/@datastructures-js/priority-queue) 6 | 7 | A performant priority queue implementation using a Heap data structure. 8 | 9 | 10 | 11 | # Contents 12 | * [Install](#install) 13 | * [require](#require) 14 | * [import](#import) 15 | * [API](#api) 16 | * [constructor](#constructor) 17 | * [.enqueue](#enqueue) 18 | * [.front](#front) 19 | * [.back](#back) 20 | * [.dequeue](#dequeue) 21 | * [.isEmpty](#isEmpty) 22 | * [.size](#size) 23 | * [.toArray](#toarray) 24 | * [.clear](#clear) 25 | * [Build](#build) 26 | * [License](#license) 27 | 28 | ## Install 29 | 30 | ```sh 31 | npm install --save @datastructures-js/priority-queue 32 | ``` 33 | 34 | ## API 35 | PriorityQueue in this repo is implemented as 3 types: 36 | 37 | - **PriorityQueue** that accepts a custom comparator between elements. 38 | - **MinPriorityQueue** which considers an element with smaller priority number as higher in priority. 39 | - **MaxPriorityQueue** which cosiders an element with bigger priority number as higher in priority. 40 | 41 | ### require 42 | 43 | ```js 44 | const { 45 | PriorityQueue, 46 | MinPriorityQueue, 47 | MaxPriorityQueue 48 | } = require('@datastructures-js/priority-queue'); 49 | ``` 50 | 51 | ### import 52 | 53 | ```js 54 | import { 55 | PriorityQueue, 56 | MinPriorityQueue, 57 | MaxPriorityQueue, 58 | PriorityQueueOptions, // queue options interface 59 | PriorityQueueItem // queue item interface for min/max queue 60 | } from '@datastructures-js/priority-queue'; 61 | ``` 62 | 63 | ### constructor 64 | #### PriorityQueue 65 | The constructor requires a compare callback to compare between queue elements. compare works similar to javascript sort callback: returning a number less or equal 0, means do not swap. 66 | 67 | ##### JS 68 | ```js 69 | // empty queue with comparator 70 | const employeesQueue = new PriorityQueue({ 71 | compare: (e1, e2) => { 72 | if (e1.salary > e2.salary) return -1; // do not swap 73 | if (e1.salary < e2.salary) return 1; // swap 74 | 75 | // salaries are the same, compare rank 76 | return e1.rank < e2.rank ? 1 : -1; 77 | } 78 | }); 79 | ``` 80 | 81 | ##### TS 82 | ```js 83 | // queued element type 84 | interface Employee { 85 | name: string; 86 | salary: number; 87 | rank: number; 88 | } 89 | 90 | // empty queue with comparator 91 | const employeesQueue = new PriorityQueue({ 92 | compare: (e1: Employee, e2: Employee): number => { 93 | if (e1.salary > e2.salary) return -1; // do not swap 94 | if (e1.salary < e2.salary) return 1; // swap 95 | 96 | // salaries are the same, compare rank 97 | return e1.rank < e2.rank ? 1 : -1; 98 | } 99 | }); 100 | ``` 101 | 102 | #### MinPriorityQueue/MaxPriorityQueue 103 | The constructor accepts a priority callback option to get the numeric priority from the queued element. If not passed, the constructor adds a default priority callback that returns the numeric value of the element itself. Use this queue type when the priority is a known value and does not require complex comparison. 104 | 105 | ##### JS 106 | ```js 107 | // empty queue with priority is the element value itself. 108 | const numbersQueue = new MinPriorityQueue(); 109 | 110 | // empty queue, will provide priority in .enqueue 111 | const patientsQueue = new MinPriorityQueue(); 112 | 113 | // empty queue with priority returned from a prop of the queued object 114 | const biddersQueue = new MaxPriorityQueue({ priority: (bid) => bid.value }); 115 | ``` 116 | 117 | ##### TS 118 | ```js 119 | const numbersQueue = new MinPriorityQueue(); 120 | 121 | const patientsQueue = new MinPriorityQueue(); 122 | 123 | interface Bid { 124 | name: string; 125 | value: number; 126 | } 127 | const biddersQueue = new MaxPriorityQueue({ 128 | priority: (bid: Bid) => bid.value 129 | }); 130 | ``` 131 | 132 | ### .enqueue 133 | #### PriorityQueue - .enqueue(element) 134 | adds an element based on its comparison with other elements in the queue. 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 |
paramsreturnruntime
element: TPriorityQueue<T>O(log(n))
148 | 149 | ```js 150 | employeesQueue 151 | .enqueue({ name: 'employee 1', salary: 2000, rank: 1 }) 152 | .enqueue({ name: 'employee 2', salary: 1500, rank: 0 }) 153 | .enqueue({ name: 'employee 3', salary: 4000, rank: 4 }) 154 | .enqueue({ name: 'employee 4', salary: 2000, rank: 2 }) 155 | .enqueue({ name: 'employee 5', salary: 3000, rank: 3 }); 156 | ``` 157 | 158 | #### MinPriorityQueue/MaxPriorityQueue - .enqueue(element[, priority]) 159 | adds an element with a numeric priority to the queue. Priority is not required here if a priority callback has been provided in the constructor. If passed here with a constructor callback, it will override the callback. 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 174 | 175 | 176 |
paramsreturnruntime
169 | element: T 170 |
171 | priority: number 172 |
MinPriorityQueue<T> | MaxPriorityQueue<T>O(log(n))
177 | 178 | ```js 179 | // MinPriorityQueue Example, where priority is the number element itself 180 | numbersQueue 181 | .enqueue(10) 182 | .enqueue(-7) 183 | .enqueue(2) 184 | .enqueue(-1) 185 | .enqueue(-17) 186 | .enqueue(33); 187 | 188 | // MinPriorityQueue Example, where priority is the patient's turn 189 | patientsQueue 190 | .enqueue('patient y', 1) // highest priority 191 | .enqueue('patient z', 3) 192 | .enqueue('patient w', 4) // lowest priority 193 | .enqueue('patient x', 2); 194 | 195 | // MaxPriorityQueue Example, where priority is the bid's value. 196 | biddersQueue 197 | .enqueue({ name: 'bidder y', value: 1000 }) // lowest priority 198 | .enqueue({ name: 'bidder w', value: 2500 }) 199 | .enqueue({ name: 'bidder z', value: 3500 }) // highest priority 200 | .enqueue({ name: 'bidder x', value: 3000 }); 201 | ``` 202 | 203 | ### .front() 204 | returns the element with highest priority in the queue. 205 | 206 | #### PriorityQueue 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 |
returnruntime
TO(1)
218 | 219 | ```js 220 | console.log(employeesQueue.dequeue()); // { name: 'employee 3', salary: 4000, rank: 4 } 221 | ``` 222 | 223 | #### MinPriorityQueue/MaxPriorityQueue 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 |
returnruntime
PriorityQueueItem<T>O(1)
235 | 236 | ```js 237 | console.log(numbersQueue.front()); // { priority: -17, element: -17 } 238 | 239 | console.log(patientsQueue.front()); // { priority: 1, element: 'patient y' } 240 | 241 | console.log(biddersQueue.front()); // { priority: 3500, element: { name: 'bidder z', value: 3500 } } 242 | ``` 243 | 244 | 245 | ### .back() 246 | returns an element with a lowest priority in the queue. 247 | 248 | #### PriorityQueue 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 |
returnruntime
TO(1)
260 | 261 | ```js 262 | console.log(employeesQueue.back()); // { name: 'employee 2', salary: 1500, rank: 0 } 263 | ``` 264 | 265 | #### MinPriorityQueue/MaxPriorityQueue 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 |
returnruntime
PriorityQueueItem<T>O(1)
277 | 278 | ```js 279 | console.log(numbersQueue.back()); // { priority: 33, element: 33 } 280 | 281 | patientsQueue.enqueue('patient m', 4); // lowest priority 282 | patientsQueue.enqueue('patient c', 4); // lowest priority 283 | console.log(patientsQueue.back()); // { priority: 4, element: 'patient c' } 284 | 285 | biddersQueue.enqueue({ name: 'bidder m', value: 1000 }); // lowest priority 286 | biddersQueue.enqueue({ name: 'bidder c', value: 1000 }); // lowest priority 287 | console.log(biddersQueue.back()); // { priority: 1000, element: { name: 'bidder y', value: 1000 } } 288 | ``` 289 | 290 | 291 | ### .dequeue() 292 | removes and returns the element with highest priority in the queue. 293 | 294 | #### PriorityQueue 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 |
returnruntime
TO(log(n))
306 | 307 | ```js 308 | console.log(employeesQueue.dequeue()); // { name: 'employee 3', salary: 4000, rank: 4 } 309 | console.log(employeesQueue.dequeue()); // { name: 'employee 5', salary: 3000, rank: 3 } 310 | console.log(employeesQueue.dequeue()); // { name: 'employee 4', salary: 2000, rank: 2 } 311 | console.log(employeesQueue.dequeue()); // { name: 'employee 1', salary: 2000, rank: 1 } 312 | console.log(employeesQueue.dequeue()); // { name: 'employee 2', salary: 1500, rank: 0 } 313 | ``` 314 | 315 | #### MinPriorityQueue/MaxPriorityQueue 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 |
returnruntime
PriorityQueueItem<T>O(log(n))
327 | 328 | ```js 329 | console.log(numbersQueue.dequeue()); // { priority: -17, element: -17 } 330 | console.log(numbersQueue.front()); // { priority: -7, element: -7 } 331 | 332 | console.log(patientsQueue.dequeue()); // { priority: 1, element: 'patient y' } 333 | console.log(patientsQueue.front()); // { priority: 2, element: 'patient x' } 334 | 335 | console.log(biddersQueue.dequeue()); // { priority: 3500, element: { name: 'bidder z', value: 3500 } } 336 | console.log(biddersQueue.front()); // { priority: 3000, element: { name: 'bidder x', value: 3000 } } 337 | ``` 338 | 339 | ### .isEmpty() 340 | checks if the queue is empty. 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 |
returnruntime
booleanO(1)
352 | 353 | ```js 354 | console.log(numbersQueue.isEmpty()); // false 355 | 356 | console.log(patientsQueue.isEmpty()); // false 357 | 358 | console.log(biddersQueue.isEmpty()); // false 359 | ``` 360 | 361 | ### .size() 362 | returns the number of elements in the queue. 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 |
returnruntime
numberO(1)
374 | 375 | ```js 376 | console.log(numbersQueue.size()); // 5 377 | 378 | console.log(patientsQueue.size()); // 5 379 | 380 | console.log(biddersQueue.size()); // 5 381 | ``` 382 | 383 | ### .toArray() 384 | returns a sorted array of elements by their priorities from highest to lowest. 385 | 386 | #### PriorityQueue 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 |
returnruntime
T[]O(n*log(n))
398 | 399 | ```js 400 | console.log(employeesQueue.toArray()); 401 | /* 402 | [ 403 | { name: 'employee 3', salary: 4000, rank: 4 }, 404 | { name: 'employee 5', salary: 3000, rank: 3 }, 405 | { name: 'employee 4', salary: 2000, rank: 2 }, 406 | { name: 'employee 1', salary: 2000, rank: 1 }, 407 | { name: 'employee 2', salary: 1500, rank: 0 } 408 | ] 409 | */ 410 | ``` 411 | 412 | #### MinPriorityQueue/MaxPriorityQueue 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 |
returnruntime
PriorityQueueItem<T>[]O(n*log(n))
424 | 425 | ```js 426 | console.log(numbersQueue.toArray()); 427 | /* 428 | [ 429 | { priority: -7, element: -7 }, 430 | { priority: -1, element: -1 }, 431 | { priority: 2, element: 2 }, 432 | { priority: 10, element: 10 }, 433 | { priority: 33, element: 33 } 434 | ] 435 | */ 436 | 437 | console.log(patientsQueue.toArray()); 438 | /* 439 | [ 440 | { priority: 2, element: 'patient x' }, 441 | { priority: 3, element: 'patient z' }, 442 | { priority: 4, element: 'patient c' }, 443 | { priority: 4, element: 'patient w' }, 444 | { priority: 4, element: 'patient m' } 445 | ] 446 | */ 447 | 448 | console.log(biddersQueue.toArray()); 449 | /* 450 | [ 451 | { priority: 3000, element: { name: 'bidder x', value: 3000 } }, 452 | { priority: 2500, element: { name: 'bidder w', value: 2500 } }, 453 | { priority: 1000, element: { name: 'bidder y', value: 1000 } }, 454 | { priority: 1000, element: { name: 'bidder m', value: 1000 } }, 455 | { priority: 1000, element: { name: 'bidder c', value: 1000 } } 456 | ] 457 | */ 458 | ``` 459 | 460 | ### .clear() 461 | clears all elements in the queue. 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 |
runtime
O(1)
471 | 472 | 473 | ```js 474 | numbersQueue.clear(); 475 | console.log(numbersQueue.size()); // 0 476 | console.log(numbersQueue.front()); // null 477 | console.log(numbersQueue.dequeue()); // null 478 | 479 | patientsQueue.clear(); 480 | console.log(patientsQueue.size()); // 0 481 | console.log(patientsQueue.front()); // null 482 | console.log(patientsQueue.dequeue()); // null 483 | 484 | biddersQueue.clear(); 485 | console.log(biddersQueue.size()); // 0 486 | console.log(biddersQueue.front()); // null 487 | console.log(biddersQueue.dequeue()); // null 488 | ``` 489 | 490 | ## Build 491 | ``` 492 | grunt build 493 | ``` 494 | 495 | ## License 496 | The MIT License. Full License is [here](https://github.com/datastructures-js/priority-queue/blob/master/LICENSE) 497 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/index.d.ts: -------------------------------------------------------------------------------- 1 | import { PriorityQueue, PriorityQueueOptions, PriorityQueueItem } from './src/priorityQueue'; 2 | import { MinPriorityQueue } from './src/minPriorityQueue'; 3 | import { MaxPriorityQueue } from './src/maxPriorityQueue'; 4 | 5 | export { PriorityQueue } 6 | export { PriorityQueueOptions } 7 | export { PriorityQueueItem } 8 | export { MinPriorityQueue } 9 | export { MaxPriorityQueue } 10 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/index.js: -------------------------------------------------------------------------------- 1 | const { MinPriorityQueue } = require('./src/minPriorityQueue'); 2 | const { MaxPriorityQueue } = require('./src/maxPriorityQueue'); 3 | const { PriorityQueue } = require('./src/priorityQueue') 4 | 5 | module.exports = { MinPriorityQueue, MaxPriorityQueue, PriorityQueue }; 6 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "@datastructures-js/priority-queue", 3 | "_id": "@datastructures-js/priority-queue@5.3.0", 4 | "_inBundle": false, 5 | "_integrity": "sha512-0Dl0UooE9Uzz85qBP46HTjQHS5GN7NMNluN5/nMfxQAndG/1eNBJpBntLGT5QJarvMO3poLNBJzA3S4GPajp+w==", 6 | "_location": "/@datastructures-js/priority-queue", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "tag", 10 | "registry": true, 11 | "raw": "@datastructures-js/priority-queue", 12 | "name": "@datastructures-js/priority-queue", 13 | "escapedName": "@datastructures-js%2fpriority-queue", 14 | "scope": "@datastructures-js", 15 | "rawSpec": "", 16 | "saveSpec": null, 17 | "fetchSpec": "latest" 18 | }, 19 | "_requiredBy": [ 20 | "#USER", 21 | "/" 22 | ], 23 | "_resolved": "https://registry.npmjs.org/@datastructures-js/priority-queue/-/priority-queue-5.3.0.tgz", 24 | "_shasum": "89afce79a19a3226c12cc6e9288f94ff60af26cf", 25 | "_spec": "@datastructures-js/priority-queue", 26 | "_where": "/Users/sadanandpaim/Documents/sadanand/projects/DSA", 27 | "author": { 28 | "name": "Eyas Ranjous", 29 | "email": "eyas.ranjous@gmail.com" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/datastructures-js/priority-queue/issues" 33 | }, 34 | "bundleDependencies": false, 35 | "dependencies": { 36 | "@datastructures-js/heap": "^3.2.0" 37 | }, 38 | "deprecated": false, 39 | "description": "a performant priority queue implementation using a Heap data structure.", 40 | "devDependencies": { 41 | "chai": "^4.2.0", 42 | "eslint": "^6.7.2", 43 | "eslint-config-airbnb-base": "^14.0.0", 44 | "eslint-plugin-import": "^2.19.1", 45 | "grunt": "^1.0.4", 46 | "grunt-eslint": "^22.0.0", 47 | "grunt-mocha-istanbul": "^5.0.2", 48 | "grunt-mocha-test": "^0.13.3", 49 | "istanbul": "^0.4.5", 50 | "mocha": "^6.2.2" 51 | }, 52 | "homepage": "https://github.com/datastructures-js/priority-queue#readme", 53 | "keywords": [ 54 | "queue", 55 | "priority queue", 56 | "priority queue es6", 57 | "priority queue js" 58 | ], 59 | "license": "MIT", 60 | "main": "index.js", 61 | "name": "@datastructures-js/priority-queue", 62 | "repository": { 63 | "type": "git", 64 | "url": "git+https://github.com/datastructures-js/priority-queue.git" 65 | }, 66 | "scripts": { 67 | "test": "grunt test" 68 | }, 69 | "version": "5.3.0" 70 | } 71 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/src/maxPriorityQueue.d.ts: -------------------------------------------------------------------------------- 1 | import { PriorityQueue } from './priorityQueue'; 2 | 3 | export class MaxPriorityQueue extends PriorityQueue {} 4 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/src/maxPriorityQueue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright 2020 Eyas Ranjous 3 | * @license MIT 4 | */ 5 | 6 | const { MaxHeap } = require('@datastructures-js/heap'); 7 | const { PriorityQueue } = require('./priorityQueue'); 8 | 9 | /** 10 | * @class MaxPriorityQueue 11 | * @extends PriorityQueue 12 | */ 13 | class MaxPriorityQueue extends PriorityQueue { 14 | constructor(options) { 15 | super(options); 16 | if (!this._compare) { 17 | this._heap = new MaxHeap(); 18 | } 19 | } 20 | } 21 | 22 | exports.MaxPriorityQueue = MaxPriorityQueue; 23 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/src/minPriorityQueue.d.ts: -------------------------------------------------------------------------------- 1 | import { PriorityQueue } from './priorityQueue'; 2 | 3 | export class MinPriorityQueue extends PriorityQueue {} 4 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/src/minPriorityQueue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright 2020 Eyas Ranjous 3 | * @license MIT 4 | */ 5 | 6 | const { MinHeap } = require('@datastructures-js/heap'); 7 | const { PriorityQueue } = require('./priorityQueue'); 8 | 9 | /** 10 | * @class MinPriorityQueue 11 | * @extends PriorityQueue 12 | */ 13 | class MinPriorityQueue extends PriorityQueue { 14 | constructor(options) { 15 | super(options); 16 | if (!this._compare) { 17 | this._heap = new MinHeap(); 18 | } 19 | } 20 | } 21 | 22 | exports.MinPriorityQueue = MinPriorityQueue; 23 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/src/priorityQueue.d.ts: -------------------------------------------------------------------------------- 1 | export interface PriorityQueueOptions { 2 | priority?: (element: T) => number; 3 | compare?: (a: T, b: T) => number; 4 | } 5 | 6 | export interface PriorityQueueItem { 7 | priority: number; 8 | element: T; 9 | } 10 | 11 | export abstract class PriorityQueue { 12 | constructor(options?: PriorityQueueOptions); 13 | size(): number; 14 | isEmpty(): boolean; 15 | front(): PriorityQueueItem | T; 16 | back(): PriorityQueueItem | T; 17 | enqueue(element: T, priority?: number): PriorityQueue; 18 | dequeue(): PriorityQueueItem | T; 19 | toArray(): (PriorityQueueItem | T)[]; 20 | clear(): void; 21 | } 22 | -------------------------------------------------------------------------------- /node_modules/@datastructures-js/priority-queue/src/priorityQueue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright 2020 Eyas Ranjous 3 | * @license MIT 4 | */ 5 | 6 | const { CustomHeap } = require('@datastructures-js/heap'); 7 | 8 | /** 9 | * @class PriorityQueue 10 | */ 11 | class PriorityQueue { 12 | /** 13 | * Creates a priority queue 14 | * @public 15 | * @params {object} [options] 16 | */ 17 | constructor(options = {}) { 18 | const { priority, compare } = options; 19 | if (compare) { 20 | if (typeof compare !== 'function') { 21 | throw new Error('.constructor expects a valid compare function'); 22 | } 23 | this._compare = compare; 24 | this._heap = new CustomHeap(this._compare); 25 | } else { 26 | if (priority !== undefined && typeof priority !== 'function') { 27 | throw new Error('.constructor expects a valid priority function'); 28 | } 29 | 30 | this._priority = priority || ((el) => +el); 31 | } 32 | } 33 | 34 | /** 35 | * @private 36 | * @returns {object} 37 | */ 38 | _getElementWithPriority(node) { 39 | return { 40 | priority: node.key, 41 | element: node.value 42 | }; 43 | } 44 | 45 | /** 46 | * @public 47 | * @returns {number} 48 | */ 49 | size() { 50 | return this._heap.size(); 51 | } 52 | 53 | /** 54 | * @public 55 | * @returns {boolean} 56 | */ 57 | isEmpty() { 58 | return this._heap.isEmpty(); 59 | } 60 | 61 | /** 62 | * Returns an element with highest priority in the queue 63 | * @public 64 | * @returns {object} 65 | */ 66 | front() { 67 | if (this.isEmpty()) return null; 68 | 69 | if (this._compare) { 70 | return this._heap.root(); 71 | } 72 | 73 | return this._getElementWithPriority(this._heap.root()); 74 | } 75 | 76 | /** 77 | * Returns an element with lowest priority in the queue 78 | * @public 79 | * @returns {object} 80 | */ 81 | back() { 82 | if (this.isEmpty()) return null; 83 | 84 | if (this._compare) { 85 | return this._heap.leaf(); 86 | } 87 | 88 | return this._getElementWithPriority(this._heap.leaf()); 89 | } 90 | 91 | /** 92 | * Adds an element to the queue 93 | * @public 94 | * @param {any} element 95 | * @param {number} p - priority 96 | * @throws {Error} if priority is not a valid number 97 | */ 98 | enqueue(element, p) { 99 | if (this._compare) { 100 | this._heap.insert(element); 101 | return this; 102 | } 103 | 104 | if (p && Number.isNaN(+p)) { 105 | throw new Error('.enqueue expects a numeric priority'); 106 | } 107 | 108 | if (Number.isNaN(+p) && Number.isNaN(this._priority(element))) { 109 | throw new Error( 110 | '.enqueue expects a numeric priority ' 111 | + 'or a constructor callback that returns a number' 112 | ); 113 | } 114 | 115 | const priority = !Number.isNaN(+p) ? p : this._priority(element); 116 | this._heap.insert(+priority, element); 117 | return this; 118 | } 119 | 120 | /** 121 | * Removes and returns an element with highest priority in the queue 122 | * @public 123 | * @returns {object} 124 | */ 125 | dequeue() { 126 | if (this.isEmpty()) return null; 127 | 128 | if (this._compare) { 129 | return this._heap.extractRoot(); 130 | } 131 | 132 | return this._getElementWithPriority(this._heap.extractRoot()); 133 | } 134 | 135 | /** 136 | * Returns a sorted list of elements from highest to lowest priority 137 | * @public 138 | * @returns {array} 139 | */ 140 | toArray() { 141 | if (this._compare) { 142 | return this._heap.clone().sort().reverse(); 143 | } 144 | 145 | return this._heap 146 | .clone() 147 | .sort() 148 | .map((n) => this._getElementWithPriority(n)) 149 | .reverse(); 150 | } 151 | 152 | /** 153 | * Clears the queue 154 | * @public 155 | */ 156 | clear() { 157 | this._heap.clear(); 158 | } 159 | } 160 | 161 | exports.PriorityQueue = PriorityQueue; 162 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@datastructures-js/heap": { 6 | "version": "3.2.0", 7 | "resolved": "https://registry.npmjs.org/@datastructures-js/heap/-/heap-3.2.0.tgz", 8 | "integrity": "sha512-FcU5ZAyb+VIOZz1HABsJUsbJi2ZyUDO7aoe97hq4d3tK3z8nMgwdxf5bO0gafR0ExFi18YTspntqHLzt4XOgnA==" 9 | }, 10 | "@datastructures-js/priority-queue": { 11 | "version": "5.3.0", 12 | "resolved": "https://registry.npmjs.org/@datastructures-js/priority-queue/-/priority-queue-5.3.0.tgz", 13 | "integrity": "sha512-0Dl0UooE9Uzz85qBP46HTjQHS5GN7NMNluN5/nMfxQAndG/1eNBJpBntLGT5QJarvMO3poLNBJzA3S4GPajp+w==", 14 | "requires": { 15 | "@datastructures-js/heap": "^3.2.0" 16 | } 17 | } 18 | } 19 | } 20 | --------------------------------------------------------------------------------