├── 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 | [](https://travis-ci.org/datastructures-js/heap)
3 | [](https://www.npmjs.com/package/@datastructures-js/heap)
4 | [](https://www.npmjs.com/package/@datastructures-js/heap) [](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 | Min Heap | Max Heap |
12 |
13 |
14 |
15 | |
16 |
17 |
18 | |
19 |
20 |
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 | params |
101 | return |
102 | runtime |
103 |
104 |
105 |
106 | key: T (number | string)
107 |
108 | value: U (any)
109 | |
110 | MinHeap<T, U> | MaxHeap<T, U> |
111 | O(log(n)) |
112 |
113 |
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 | params |
139 | return |
140 | runtime |
141 |
142 |
143 |
144 | key: T
145 | |
146 | CustomHeap<T> |
147 | O(log(n)) |
148 |
149 |
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 | return |
169 | runtime |
170 |
171 |
172 | number | string | HeapNode |
173 | O(log(n)) |
174 |
175 |
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 | return |
191 | runtime |
192 |
193 |
194 | T |
195 | O(log(n)) |
196 |
197 |
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 | return |
212 | runtime |
213 |
214 |
215 | number | string | HeapNode |
216 | O(1) |
217 |
218 |
219 |
220 | ```js
221 | console.log(minHeap.root()); // 50
222 |
223 | console.log(maxHeap.root()); // 'k'
224 | ```
225 |
226 | ##### CustomHeap
227 |
228 |
229 | return |
230 | runtime |
231 |
232 |
233 | T |
234 | O(1) |
235 |
236 |
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 | return |
249 | runtime |
250 |
251 |
252 | number | string | HeapNode |
253 | O(1) |
254 |
255 |
256 |
257 | ```js
258 | console.log(minHeap.leaf()); // 90
259 |
260 | console.log(maxHeap.leaf()); // 'b'
261 | ```
262 |
263 | ##### CustomHeap
264 |
265 |
266 | return |
267 | runtime |
268 |
269 |
270 | T |
271 | O(1) |
272 |
273 |
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 | return |
285 | runtime |
286 |
287 |
288 | number |
289 | O(1) |
290 |
291 |
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 | return |
305 | runtime |
306 |
307 |
308 | MinHeap | MaxHeap | CustomHeap |
309 | O(n) |
310 |
311 |
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 | return |
336 | runtime |
337 |
338 |
339 | boolean |
340 | O(log(n)) |
341 |
342 |
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 | return |
358 | runtime |
359 |
360 |
361 | MinHeap | MaxHeap | CustomHeap |
362 | O(log(n)) |
363 |
364 |
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 | return |
382 | runtime |
383 |
384 |
385 | array<number|string|HeapNode> |
386 | O(n*log(n)) |
387 |
388 |
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 | return |
427 | runtime |
428 |
429 |
430 | array<T> |
431 | O(n*log(n)) |
432 |
433 |
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 | runtime |
457 |
458 |
459 | O(1) |
460 |
461 |
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 | params |
481 | return |
482 | runtime |
483 |
484 |
485 | list: array<number | string | HeapNode> |
486 | MinHeap | MaxHeap |
487 | O(n) |
488 |
489 |
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 | params |
560 | return |
561 | runtime |
562 |
563 |
564 |
565 | list: array<T>
566 |
567 | comparator: (a: T, b: T) => number
568 | |
569 | CustomHeap<T> |
570 | O(n) |
571 |
572 |
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 | params |
607 | return |
608 | runtime |
609 |
610 |
611 |
612 | list: array<number | string | HeapNode>
613 | |
614 | boolean |
615 | O(log(n)) |
616 |
617 |
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 | params |
642 | return |
643 | runtime |
644 |
645 |
646 |
647 | list: array<T>
648 |
649 | comparator: (a: T, b: T) => number
650 | |
651 | boolean |
652 | O(log(n)) |
653 |
654 |
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 | [](https://travis-ci.org/datastructures-js/priority-queue)
4 | [](https://www.npmjs.com/package/@datastructures-js/priority-queue)
5 | [](https://www.npmjs.com/package/@datastructures-js/priority-queue) [](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 | params |
139 | return |
140 | runtime |
141 |
142 |
143 | element: T |
144 | PriorityQueue<T> |
145 | O(log(n)) |
146 |
147 |
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 | params |
164 | return |
165 | runtime |
166 |
167 |
168 |
169 | element: T
170 |
171 | priority: number
172 | |
173 | MinPriorityQueue<T> | MaxPriorityQueue<T> |
174 | O(log(n)) |
175 |
176 |
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 | return |
211 | runtime |
212 |
213 |
214 | T |
215 | O(1) |
216 |
217 |
218 |
219 | ```js
220 | console.log(employeesQueue.dequeue()); // { name: 'employee 3', salary: 4000, rank: 4 }
221 | ```
222 |
223 | #### MinPriorityQueue/MaxPriorityQueue
224 |
225 |
226 |
227 | return |
228 | runtime |
229 |
230 |
231 | PriorityQueueItem<T> |
232 | O(1) |
233 |
234 |
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 | return |
253 | runtime |
254 |
255 |
256 | T |
257 | O(1) |
258 |
259 |
260 |
261 | ```js
262 | console.log(employeesQueue.back()); // { name: 'employee 2', salary: 1500, rank: 0 }
263 | ```
264 |
265 | #### MinPriorityQueue/MaxPriorityQueue
266 |
267 |
268 |
269 | return |
270 | runtime |
271 |
272 |
273 | PriorityQueueItem<T> |
274 | O(1) |
275 |
276 |
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 | return |
299 | runtime |
300 |
301 |
302 | T |
303 | O(log(n)) |
304 |
305 |
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 | return |
320 | runtime |
321 |
322 |
323 | PriorityQueueItem<T> |
324 | O(log(n)) |
325 |
326 |
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 | return |
345 | runtime |
346 |
347 |
348 | boolean |
349 | O(1) |
350 |
351 |
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 | return |
367 | runtime |
368 |
369 |
370 | number |
371 | O(1) |
372 |
373 |
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 | return |
391 | runtime |
392 |
393 |
394 | T[] |
395 | O(n*log(n)) |
396 |
397 |
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 | return |
417 | runtime |
418 |
419 |
420 | PriorityQueueItem<T>[] |
421 | O(n*log(n)) |
422 |
423 |
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 | runtime |
466 |
467 |
468 | O(1) |
469 |
470 |
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 |
--------------------------------------------------------------------------------