From bb6a429cb5df13400f8b63e2705e424a84aff6e1 Mon Sep 17 00:00:00 2001 From: sandeepsj <36895341+sandeepsj@users.noreply.github.com> Date: Mon, 3 Jun 2019 19:24:10 +0530 Subject: [PATCH 01/26] Create Hamiltonean Cycles --- Backtracking/Hamiltonean Cycles | 1 + 1 file changed, 1 insertion(+) create mode 100644 Backtracking/Hamiltonean Cycles diff --git a/Backtracking/Hamiltonean Cycles b/Backtracking/Hamiltonean Cycles new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/Backtracking/Hamiltonean Cycles @@ -0,0 +1 @@ + From 5a5ebb8ea5f8ab123a135b3b065c5b445ec1546c Mon Sep 17 00:00:00 2001 From: sandeepsj <36895341+sandeepsj@users.noreply.github.com> Date: Mon, 3 Jun 2019 19:25:04 +0530 Subject: [PATCH 02/26] Delete Hamiltonean Cycles --- Backtracking/Hamiltonean Cycles | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Backtracking/Hamiltonean Cycles diff --git a/Backtracking/Hamiltonean Cycles b/Backtracking/Hamiltonean Cycles deleted file mode 100644 index 8b137891..00000000 --- a/Backtracking/Hamiltonean Cycles +++ /dev/null @@ -1 +0,0 @@ - From bc4106c36dafab099a2dd2f41ca180c8637fa071 Mon Sep 17 00:00:00 2001 From: sandeepsj <36895341+sandeepsj@users.noreply.github.com> Date: Mon, 3 Jun 2019 19:26:07 +0530 Subject: [PATCH 03/26] Create readme --- Backtracking/Hamiltonean Cycles/readme | 1 + 1 file changed, 1 insertion(+) create mode 100644 Backtracking/Hamiltonean Cycles/readme diff --git a/Backtracking/Hamiltonean Cycles/readme b/Backtracking/Hamiltonean Cycles/readme new file mode 100644 index 00000000..78981922 --- /dev/null +++ b/Backtracking/Hamiltonean Cycles/readme @@ -0,0 +1 @@ +a From c93c4d878fd6871067c5e811dd3ccbaa8594a691 Mon Sep 17 00:00:00 2001 From: sandeepsj0000 Date: Mon, 3 Jun 2019 19:34:09 +0530 Subject: [PATCH 04/26] Adding algorithm hamiltonean Cycle --- Backtracking/Hamiltonean Cycles/Code.java | 102 ++++++++++++++++++++++ Backtracking/Hamiltonean Cycles/readme | 1 - 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 Backtracking/Hamiltonean Cycles/Code.java delete mode 100644 Backtracking/Hamiltonean Cycles/readme diff --git a/Backtracking/Hamiltonean Cycles/Code.java b/Backtracking/Hamiltonean Cycles/Code.java new file mode 100644 index 00000000..76c564cd --- /dev/null +++ b/Backtracking/Hamiltonean Cycles/Code.java @@ -0,0 +1,102 @@ +//A Hamiltonian cycle is a cycle in an undirected or directed graph that visits each vertex exactly once. +// import visualization libraries { +import org.algorithm_visualizer.*; +import java.util.Random; +// } + +class Main { + // define tracer variables { + GraphTracer graphTracer=new GraphTracer("GraphTracer"); + LogTracer logTracer = new LogTracer("Console"); + // } + int n=8; + int x[]; + int found=0; + int vis[]; + int[][] adjacencyMatrix; + void ham(int k) { + while(true) + { + nextVal(k); + if(x[k]==-1) + return; + if(k==n-1) + { + graphTracer.visit(x[0],x[k]); + graphTracer.delay(); + found=1; + //Printint the cycle{ + for(int i=0;i Date: Mon, 3 Jun 2019 19:43:16 +0530 Subject: [PATCH 05/26] Create README.md --- Backtracking/Hamiltonean Cycles/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Backtracking/Hamiltonean Cycles/README.md diff --git a/Backtracking/Hamiltonean Cycles/README.md b/Backtracking/Hamiltonean Cycles/README.md new file mode 100644 index 00000000..259deff0 --- /dev/null +++ b/Backtracking/Hamiltonean Cycles/README.md @@ -0,0 +1,5 @@ +# Hamiltonean Cycles +A **Hamiltonean Path** is a path in an undirected or directed graph that visits each vertex exactly once. A **Hamiltonian cycle** (or Hamiltonian circuit) is a Hamiltonian path that is a cycle. Determining whether such paths and cycles exist in graphs is the Hamiltonian path problem, which is NP-complete. + +## References +-[Wikipedia](https://en.wikipedia.org/wiki/Hamiltonian_path) \ No newline at end of file From 3ed3d803db75d63b538a1c25aa875c2f4327b848 Mon Sep 17 00:00:00 2001 From: sandeepsj0000 Date: Mon, 3 Jun 2019 19:50:41 +0530 Subject: [PATCH 06/26] Delete README.md --- Backtracking/Hamiltonean Cycles/README.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 Backtracking/Hamiltonean Cycles/README.md diff --git a/Backtracking/Hamiltonean Cycles/README.md b/Backtracking/Hamiltonean Cycles/README.md deleted file mode 100644 index 259deff0..00000000 --- a/Backtracking/Hamiltonean Cycles/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Hamiltonean Cycles -A **Hamiltonean Path** is a path in an undirected or directed graph that visits each vertex exactly once. A **Hamiltonian cycle** (or Hamiltonian circuit) is a Hamiltonian path that is a cycle. Determining whether such paths and cycles exist in graphs is the Hamiltonian path problem, which is NP-complete. - -## References --[Wikipedia](https://en.wikipedia.org/wiki/Hamiltonian_path) \ No newline at end of file From 6ea9afe92947993f0857a799b98a00a22b2e6576 Mon Sep 17 00:00:00 2001 From: suiyueranzly Date: Tue, 4 Jun 2019 06:53:25 +0800 Subject: [PATCH 07/26] Comb Sort on Java in Brute Force\Comb Sort (#7) --- Brute Force/Comb Sort/Code.java | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Brute Force/Comb Sort/Code.java diff --git a/Brute Force/Comb Sort/Code.java b/Brute Force/Comb Sort/Code.java new file mode 100644 index 00000000..a3635aa3 --- /dev/null +++ b/Brute Force/Comb Sort/Code.java @@ -0,0 +1,69 @@ +import org.algorithm_visualizer.*; + +import java.util.Arrays; + +class Main { + + private static ChartTracer chartTracer = new ChartTracer(); + + private static LogTracer logTracer = new LogTracer("Console"); + + private static Array1DTracer tracer = new Array1DTracer(); + + private static Integer[] array = (Integer[]) new Randomize.Array1D(15, new Randomize.Integer(1, 20)).create(); + + public static void main(String[] args) { + tracer.set(array); + tracer.chart(chartTracer); + Layout.setRoot(new VerticalLayout(new Commander[]{chartTracer, tracer, logTracer})); + logTracer.printf("original array = %s\n", Arrays.toString(array)); + + Tracer.delay(); + + int length = array.length; + + int gap = length; + + boolean swapped; + + float shrink = 1.3f; + + do { + swapped = false; + + gap = (int) Math.floor(gap / shrink); + + if(gap < 1){ + gap = 1; + } + + for (int i = 0; i + gap < length; i++) { + tracer.select(i); + tracer.select(i + gap); + Tracer.delay(); + if (array[i] > array[i + gap]) { + swap(i, i + gap, array); + swapped = true; + } + tracer.deselect(i); + tracer.deselect(i + gap); + } + + } while (gap != 1 || swapped); + + + logTracer.printf("sorted array = %s\n", Arrays.toString(array)); + } + + private static void swap(int x, int y, Integer[] array) { + int temp = array[x]; + array[x] = array[y]; + array[y] = temp; + tracer.patch(x, array[x]); + tracer.patch(y, array[y]); + Tracer.delay(); + tracer.depatch(x); + tracer.depatch(y); + } + +} From 9423b2ade394577de2d166b9e43d79169b650e46 Mon Sep 17 00:00:00 2001 From: Sandeep S J Date: Thu, 6 Jun 2019 23:44:03 +0530 Subject: [PATCH 08/26] Sum of subsets (#9) * Create Code.java * Create README.md --- Backtracking/Sum of subsets/Code.java | 97 +++++++++++++++++++++++++++ Backtracking/Sum of subsets/README.md | 10 +++ 2 files changed, 107 insertions(+) create mode 100644 Backtracking/Sum of subsets/Code.java create mode 100644 Backtracking/Sum of subsets/README.md diff --git a/Backtracking/Sum of subsets/Code.java b/Backtracking/Sum of subsets/Code.java new file mode 100644 index 00000000..7c563551 --- /dev/null +++ b/Backtracking/Sum of subsets/Code.java @@ -0,0 +1,97 @@ +// import visualization libraries { +import org.algorithm_visualizer.*; +import java.util.Random; +// } + +class Main { + // define tracer variables { + Array1DTracer array1dTracer = new Array1DTracer("Set"); + LogTracer logTracer = new LogTracer("Console"); + // } + + // define input variables + int n; + int s[]; + int d; + + void solve() + { + int[] sel=new int[n+1]; + int k=0,sum=0,found=0; + sel[0]=1; + array1dTracer.select(k); + Tracer.delay(); + while(true) { + if(k=0 && sel[k]==0) + k--; + if(k<0) + break; + sel[k]=0; + array1dTracer.deselect(k); + Tracer.delay(); + sum-=s[k]; + } + k++; + if(k Date: Mon, 10 Jun 2019 02:15:06 +0900 Subject: [PATCH 09/26] Update documentation --- CONTRIBUTING.md | 22 ++++++++++++++++++++-- README.md | 7 ++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 96be9a84..08823b5a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,13 +3,16 @@ > #### Table of Contents > - [Learning About Tracers](#learning-about-tracers) > - [Running on Scratch Paper](#running-on-scratch-paper) +> - [Directory Structures](#directory-structures) > - [Creating a Pull Request](#creating-a-pull-request) +Are you a first-timer in contributing to open source? [These guidelines](https://opensource.guide/how-to-contribute/#how-to-submit-a-contribution) from GitHub might help! + ## Learning About Tracers The project [Algorithm Visualizer](https://github.com/algorithm-visualizer) has a visualization library in each supported language ([JavaScript](https://github.com/algorithm-visualizer/tracers.js), [C++](https://github.com/algorithm-visualizer/tracers.cpp), and [Java](https://github.com/algorithm-visualizer/tracers.java)) to visualize codes. -There are five tracers in the library to visualize different types of data. +There are five tracers in the library to visualize different types of data: - [Array1DTracer](https://github.com/algorithm-visualizer/algorithm-visualizer/wiki/Array1DTracer) - [Array2DTracer](https://github.com/algorithm-visualizer/algorithm-visualizer/wiki/Array2DTracer) @@ -27,6 +30,21 @@ At the bottom left corner of [algorithm-visualizer.org](https://algorithm-visual We highly encourage you to test your visualization on Scratch Paper several times before creating a pull request. +## Directory Structures + +- **Category A/** + - **Algorithm A/** + - **code.js** + - **code.cpp** + - **code.java** + - **README.md** + - **Algorithm B/** + - **Algorithm C/** + - ... +- **Category B/** +- **Category C/** +- ... + ## Creating a Pull Request 1. Fork this repository. @@ -41,7 +59,7 @@ We highly encourage you to test your visualization on Scratch Paper several time 3. Make changes. - Understand the [directory structure](https://github.com/algorithm-visualizer/algorithm-visualizer/blob/master/PROJECT_DETAILS.md#algorithms), and create or edit files accordingly. + Understand the [directory structure](#directory-structures), and create or edit files accordingly. If you want to create a directory, check out this [Stack Overflow answer](https://stackoverflow.com/questions/18773598/creating-folders-inside-github-com-repo-without-using-git). diff --git a/README.md b/README.md index 9fe9aec1..59a260a3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ # Algorithms -> `algorithms` contains algorithm visualizations. - -This repository is part of the project [Algorithm Visualizer](https://github.com/algorithm-visualizer). - -All the codes here are visualized on [algorithm-visualizer.org](https://algorithm-visualizer.org/). +> This repository is part of the project [Algorithm Visualizer](https://github.com/algorithm-visualizer). +`algorithms` contains algorithm visualizations shown on the side menu of [algorithm-visualizer.org](https://algorithm-visualizer.org/). The project currently supports JavaScript, C++, and Java. ## Contributing From f310721ed04a7868b50a26e41dfae1e2efbd477e Mon Sep 17 00:00:00 2001 From: who who who Date: Wed, 12 Jun 2019 14:46:35 +0800 Subject: [PATCH 10/26] Use Math.floor instead of Math.ceil (#10) --- Brute Force/Heapsort/code.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Brute Force/Heapsort/code.js b/Brute Force/Heapsort/code.js index 8ffed673..f1e0fca9 100644 --- a/Brute Force/Heapsort/code.js +++ b/Brute Force/Heapsort/code.js @@ -16,7 +16,7 @@ function heapSort(array, size) { let j; let temp; - for (i = Math.ceil(size / 2) - 1; i >= 0; i--) { + for (i = Math.floor(size / 2) - 1; i >= 0; i--) { heapify(array, size, i); } From ef4636934f3ac98e2256ac0fbd3cb5c7b10c5cd3 Mon Sep 17 00:00:00 2001 From: Jason Park Date: Thu, 13 Jun 2019 14:43:47 +0900 Subject: [PATCH 11/26] Adjust to the updated Randomize functions in tracers.js --- Branch and Bound/Binary Search Tree/search.js | 2 +- Branch and Bound/Binary Search/iterative.js | 4 ++-- Branch and Bound/Binary Search/recursive.js | 4 ++-- Branch and Bound/Depth-Limited Search/code.js | 1 + Brute Force/Breadth-First Search/shortestPath.js | 6 +++--- Brute Force/Breadth-First Search/tree.js | 1 + Brute Force/Bubble Sort/code.js | 2 +- Brute Force/Comb Sort/code.js | 2 +- Brute Force/Cycle Sort/code.js | 2 +- Brute Force/Depth-First Search/graph.js | 2 +- Brute Force/Depth-First Search/shortestPath.js | 6 +++--- Brute Force/Depth-First Search/weightedGraph.js | 2 +- Brute Force/Heapsort/code.js | 2 +- Brute Force/Insertion Sort/code.js | 2 +- Brute Force/PageRank/code.js | 2 +- Brute Force/Pancake Sort/code.js | 9 +++++++-- Brute Force/Selection Sort/code.js | 2 +- Brute Force/Shellsort/code.js | 2 +- Divide and Conquer/Bucket Sort/code.js | 2 +- Divide and Conquer/Counting Sort/code.js | 2 +- Divide and Conquer/Merge Sort/bottomUp.js | 4 ++-- Divide and Conquer/Merge Sort/topDown.js | 2 +- Divide and Conquer/Pigeonhole Sort/code.js | 2 +- Divide and Conquer/Quicksort/code.js | 2 +- Divide and Conquer/Radix Sort/leastSignificantDigit.js | 2 +- .../Bellman-Ford's Shortest Path/code.js | 6 +++--- .../Floyd-Warshall's Shortest Path/code.js | 2 +- Dynamic Programming/Integer Partition/code.js | 2 +- .../Longest Increasing Subsequence/code.js | 2 +- .../Longest Palindromic Subsequence/code.js | 1 + Dynamic Programming/Maximum Sum Path/code.js | 2 +- Dynamic Programming/Sliding Window/code.js | 2 +- Dynamic Programming/Z String Search/code.js | 8 ++++---- Greedy/Dijkstra's Shortest Path/code.js | 6 +++--- Greedy/Kruskal's Minimum Spanning Tree/code.js | 2 +- Greedy/Prim's Minimum Spanning Tree/code.js | 2 +- Greedy/Stable Matching/code.js | 10 +++++----- Uncategorized/Affine Cipher/code.js | 4 ++-- 38 files changed, 63 insertions(+), 55 deletions(-) diff --git a/Branch and Bound/Binary Search Tree/search.js b/Branch and Bound/Binary Search Tree/search.js index 9639f0b0..f45f5f8a 100644 --- a/Branch and Bound/Binary Search Tree/search.js +++ b/Branch and Bound/Binary Search Tree/search.js @@ -28,7 +28,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; -const key = new Randomize.Integer(0, G.length - 1).create(); // item to be searched +const key = Randomize.Integer({ min: 0, max: G.length - 1 }); // item to be searched const tracer = new GraphTracer(' Binary Search Tree '); const logger = new LogTracer(' Log '); Layout.setRoot(new VerticalLayout([tracer, logger])); diff --git a/Branch and Bound/Binary Search/iterative.js b/Branch and Bound/Binary Search/iterative.js index 72137b8a..5bb2d658 100644 --- a/Branch and Bound/Binary Search/iterative.js +++ b/Branch and Bound/Binary Search/iterative.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15, new Randomize.Integer(0, 50)).sorted().create(); +const D = Randomize.Array1D({ N: 15, value: () => Randomize.Integer({ min: 0, max: 50 }), sorted: true }); tracer.set(D); tracer.chart(chart); Tracer.delay(); @@ -44,7 +44,7 @@ function BinarySearch(array, element) { // array = sorted array, element = eleme return -1; } -const element = D[new Randomize.Integer(0, D.length - 1).create()]; +const element = D[Randomize.Integer({ min: 0, max: D.length - 1 })]; logger.println(`Using iterative binary search to find ${element}`); BinarySearch(D, element); diff --git a/Branch and Bound/Binary Search/recursive.js b/Branch and Bound/Binary Search/recursive.js index 4e4c753a..2a20e61d 100644 --- a/Branch and Bound/Binary Search/recursive.js +++ b/Branch and Bound/Binary Search/recursive.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15, new Randomize.Integer(0, 50)).sorted().create(); +const D = Randomize.Array1D({ N: 15, value: () => Randomize.Integer({ min: 0, max: 50 }), sorted: true }); tracer.set(D); tracer.chart(chart); Tracer.delay(); @@ -46,7 +46,7 @@ function BinarySearch(array, element, minIndex, maxIndex) { // array = sorted ar return -1; } -const element = D[new Randomize.Integer(0, D.length - 1).create()]; +const element = D[Randomize.Integer({ min: 0, max: D.length - 1 })]; logger.println(`Using binary search to find ${element}`); BinarySearch(D, element, 0, D.length - 1); diff --git a/Branch and Bound/Depth-Limited Search/code.js b/Branch and Bound/Depth-Limited Search/code.js index 2c61b3fc..b4f2530d 100644 --- a/Branch and Bound/Depth-Limited Search/code.js +++ b/Branch and Bound/Depth-Limited Search/code.js @@ -37,4 +37,5 @@ function DLSCount(limit, node, parent) { // node = current node, parent = previo } return child; } + logger.println(`Number of descendant is ${DLSCount(2, 0)}`); diff --git a/Brute Force/Breadth-First Search/shortestPath.js b/Brute Force/Breadth-First Search/shortestPath.js index 29544d46..bee38433 100644 --- a/Brute Force/Breadth-First Search/shortestPath.js +++ b/Brute Force/Breadth-First Search/shortestPath.js @@ -4,7 +4,7 @@ const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.log(logger); -const G = new Randomize.Graph(5, 1).directed(false).weighted().create(); +const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); @@ -36,10 +36,10 @@ function BFS() { return W[e]; } -let s = new Randomize.Integer(0, G.length - 1).create(); // s = start node +let s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node let e; // e = start node do { - e = new Randomize.Integer(0, G.length - 1).create(); + e = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (s === e); let MAX_VALUE = 0x7fffffff; logger.println(`finding the shortest path from ${s} to ${e}`); diff --git a/Brute Force/Breadth-First Search/tree.js b/Brute Force/Breadth-First Search/tree.js index 0c771d42..598a7dd1 100644 --- a/Brute Force/Breadth-First Search/tree.js +++ b/Brute Force/Breadth-First Search/tree.js @@ -37,4 +37,5 @@ function BFS(s) { // s = start node } } } + BFS(0); diff --git a/Brute Force/Bubble Sort/code.js b/Brute Force/Bubble Sort/code.js index 0aeb0ec8..136f7c97 100644 --- a/Brute Force/Bubble Sort/code.js +++ b/Brute Force/Bubble Sort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Brute Force/Comb Sort/code.js b/Brute Force/Comb Sort/code.js index 06072261..fbbdbf89 100644 --- a/Brute Force/Comb Sort/code.js +++ b/Brute Force/Comb Sort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Brute Force/Cycle Sort/code.js b/Brute Force/Cycle Sort/code.js index bb41fa34..8bc185d2 100644 --- a/Brute Force/Cycle Sort/code.js +++ b/Brute Force/Cycle Sort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Brute Force/Depth-First Search/graph.js b/Brute Force/Depth-First Search/graph.js index d7928980..eb7881de 100644 --- a/Brute Force/Depth-First Search/graph.js +++ b/Brute Force/Depth-First Search/graph.js @@ -5,7 +5,7 @@ const visitedTracer = new Array1DTracer('visited'); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([graphTracer, visitedTracer, logger])); graphTracer.log(logger); -const G = new Randomize.Graph(8, .3).directed(false).create(); +const G = Randomize.Graph({ N: 8, ratio: .3, directed: false }); graphTracer.set(G); Tracer.delay(); diff --git a/Brute Force/Depth-First Search/shortestPath.js b/Brute Force/Depth-First Search/shortestPath.js index 0b9da4e9..9403fc24 100644 --- a/Brute Force/Depth-First Search/shortestPath.js +++ b/Brute Force/Depth-First Search/shortestPath.js @@ -4,7 +4,7 @@ const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.log(logger); -const G = new Randomize.Graph(5, 1).directed(false).weighted().create(); +const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); @@ -35,10 +35,10 @@ function DFS(node, parent, weight) { // node = current node, parent = previous n Tracer.delay(); } -const s = new Randomize.Integer(0, G.length - 1).create(); // s = start node +const s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node let e; // e = end node do { - e = new Randomize.Integer(0, G.length - 1).create(); + e = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (s === e); const MAX_VALUE = Infinity; let minWeight = MAX_VALUE; diff --git a/Brute Force/Depth-First Search/weightedGraph.js b/Brute Force/Depth-First Search/weightedGraph.js index 53a25d19..c71549af 100644 --- a/Brute Force/Depth-First Search/weightedGraph.js +++ b/Brute Force/Depth-First Search/weightedGraph.js @@ -4,7 +4,7 @@ const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.log(logger); -const G = new Randomize.Graph(5, 1).directed(false).weighted().create(); +const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); diff --git a/Brute Force/Heapsort/code.js b/Brute Force/Heapsort/code.js index f1e0fca9..73832cb8 100644 --- a/Brute Force/Heapsort/code.js +++ b/Brute Force/Heapsort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(10).create(); +const D = Randomize.Array1D({ N: 10 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Brute Force/Insertion Sort/code.js b/Brute Force/Insertion Sort/code.js index a655e780..462a66cd 100644 --- a/Brute Force/Insertion Sort/code.js +++ b/Brute Force/Insertion Sort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Brute Force/PageRank/code.js b/Brute Force/PageRank/code.js index c694c08d..69e9c82d 100644 --- a/Brute Force/PageRank/code.js +++ b/Brute Force/PageRank/code.js @@ -4,7 +4,7 @@ function filledArray(length, value) { return Array(...Array(length)).map(Number.prototype.valueOf, value); } -const G = new Randomize.Graph(5, .4).create(); +const G = Randomize.Graph({ N: 5, ratio: .4 }); let ranks; const outgoingEdgeCounts = filledArray(G.length, 0); let incomingNodes; diff --git a/Brute Force/Pancake Sort/code.js b/Brute Force/Pancake Sort/code.js index d40a6a9b..f520a64a 100644 --- a/Brute Force/Pancake Sort/code.js +++ b/Brute Force/Pancake Sort/code.js @@ -4,13 +4,14 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(10).create(); +const D = Randomize.Array1D({ N: 10 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); logger.println(`original array = [${D.join(', ')}]`); const N = D.length; + function flip(start) { tracer.select(start, N - 1); Tracer.delay(); @@ -31,10 +32,14 @@ function flip(start) { } tracer.deselect(start, N - 1); } + for (let i = 0; i < N - 1; i++) { logger.println(`round ${i + 1}`); const currArr = D.slice(i, N); - const currMax = currArr.reduce((prev, curr, idx) => ((curr > prev.val) ? { idx, val: curr } : prev), { idx: 0, val: currArr[0] }); + const currMax = currArr.reduce((prev, curr, idx) => ((curr > prev.val) ? { idx, val: curr } : prev), { + idx: 0, + val: currArr[0], + }); if (currMax.idx !== 0) { // if currMax.idx === 0 that means max element already at the bottom, no flip required logger.println(`flip at ${currMax.idx + i} (step 1)`); flip(currMax.idx + i, N); diff --git a/Brute Force/Selection Sort/code.js b/Brute Force/Selection Sort/code.js index 26144ccc..d7316338 100644 --- a/Brute Force/Selection Sort/code.js +++ b/Brute Force/Selection Sort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Brute Force/Shellsort/code.js b/Brute Force/Shellsort/code.js index cdaeccaa..d13739be 100644 --- a/Brute Force/Shellsort/code.js +++ b/Brute Force/Shellsort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Divide and Conquer/Bucket Sort/code.js b/Divide and Conquer/Bucket Sort/code.js index 90a9aefd..d78e40fa 100644 --- a/Divide and Conquer/Bucket Sort/code.js +++ b/Divide and Conquer/Bucket Sort/code.js @@ -12,7 +12,7 @@ Layout.setRoot(new VerticalLayout([chartTracer, arrayTracer, bucketsTracer])); // define input variables const N = 25; // the size of an array const K = 5; // the number of buckets -const array = new Randomize.Array1D(N, new Randomize.Integer(0, 999)).create(); +const array = Randomize.Array1D({ N, value: () => Randomize.Integer({ min: 0, max: 999 }) }); (function main() { // create K buckets diff --git a/Divide and Conquer/Counting Sort/code.js b/Divide and Conquer/Counting Sort/code.js index 6303e83d..aea80f8f 100644 --- a/Divide and Conquer/Counting Sort/code.js +++ b/Divide and Conquer/Counting Sort/code.js @@ -11,7 +11,7 @@ Layout.setRoot(new VerticalLayout([arrayTracer, countsTracer, sortedArrayTracer] // define input variables const N = 20; // the size of an array -const array = new Randomize.Array1D(N, new Randomize.Integer(0, 9)).create(); +const array = Randomize.Array1D({ N, value: () => Randomize.Integer({ min: 0, max: 9 }) }); (function main() { // find the maximum value that will decide the size of counts array diff --git a/Divide and Conquer/Merge Sort/bottomUp.js b/Divide and Conquer/Merge Sort/bottomUp.js index 18a9c727..195e8f47 100644 --- a/Divide and Conquer/Merge Sort/bottomUp.js +++ b/Divide and Conquer/Merge Sort/bottomUp.js @@ -4,8 +4,8 @@ const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); const D = [ - new Randomize.Array1D(20, new Randomize.Integer(0, 50)).create(), - new Randomize.Array1D(20, new Randomize.Integer(0, 0)).create(), + Randomize.Array1D({ N: 20, value: () => Randomize.Integer({ min: 0, max: 50 }) }), + Randomize.Array1D({ N: 20, value: () => Randomize.Integer({ min: 0, max: 0 }) }), ]; tracer.set(D); diff --git a/Divide and Conquer/Merge Sort/topDown.js b/Divide and Conquer/Merge Sort/topDown.js index 177b7efc..eac4f824 100644 --- a/Divide and Conquer/Merge Sort/topDown.js +++ b/Divide and Conquer/Merge Sort/topDown.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Divide and Conquer/Pigeonhole Sort/code.js b/Divide and Conquer/Pigeonhole Sort/code.js index b3d68876..27923636 100644 --- a/Divide and Conquer/Pigeonhole Sort/code.js +++ b/Divide and Conquer/Pigeonhole Sort/code.js @@ -1,6 +1,6 @@ const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); -const A = new Randomize.Array1D(7).create(); +const A = Randomize.Array1D({ N: 7 }); const N = A.length; const tracer1 = new Array1DTracer('Array'); diff --git a/Divide and Conquer/Quicksort/code.js b/Divide and Conquer/Quicksort/code.js index 59f5fd21..0cd46345 100644 --- a/Divide and Conquer/Quicksort/code.js +++ b/Divide and Conquer/Quicksort/code.js @@ -4,7 +4,7 @@ const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([chart, tracer, logger])); -const D = new Randomize.Array1D(15).create(); +const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); diff --git a/Divide and Conquer/Radix Sort/leastSignificantDigit.js b/Divide and Conquer/Radix Sort/leastSignificantDigit.js index 4b2af6fd..7a7c21d1 100644 --- a/Divide and Conquer/Radix Sort/leastSignificantDigit.js +++ b/Divide and Conquer/Radix Sort/leastSignificantDigit.js @@ -3,7 +3,7 @@ const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); -const k = new Randomize.Array1D(10, new Randomize.Integer(1, 999)).create(); +const k = Randomize.Array1D({ N: 10, value: () => Randomize.Integer({ min: 1, max: 999 }) }); const D = [ k, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], diff --git a/Dynamic Programming/Bellman-Ford's Shortest Path/code.js b/Dynamic Programming/Bellman-Ford's Shortest Path/code.js index ef9e16ab..2bd0925c 100644 --- a/Dynamic Programming/Bellman-Ford's Shortest Path/code.js +++ b/Dynamic Programming/Bellman-Ford's Shortest Path/code.js @@ -4,7 +4,7 @@ const tracer = new GraphTracer().weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.log(logger); -const G = new Randomize.Graph(5, .5, new Randomize.Integer(-2, 5)).weighted().create(); +const G = Randomize.Graph({ N: 5, ratio: .5, value: () => Randomize.Integer({ min: -2, max: 5 }), weighted: true }); tracer.set(G); Tracer.delay(); @@ -66,7 +66,7 @@ function BELLMAN_FORD(src, dest) { return weights[dest]; } -const src = new Randomize.Integer(0, G.length - 1).create(); +const src = Randomize.Integer({ min: 0, max: G.length - 1 }); let dest; let MAX_VALUE = 0x7fffffff; let minWeight; @@ -77,7 +77,7 @@ let minWeight; */ do { - dest = new Randomize.Integer(0, G.length - 1).create(); + dest = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (src === dest); diff --git a/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js b/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js index 0b01b6ad..5c8dd7e7 100644 --- a/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js +++ b/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js @@ -4,7 +4,7 @@ const tracer = new GraphTracer().weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.log(logger); -const G = new Randomize.Graph(5, 1).weighted().create(); +const G = Randomize.Graph({ N: 5, ratio: 1, weighted: true }); tracer.set(G); Tracer.delay(); diff --git a/Dynamic Programming/Integer Partition/code.js b/Dynamic Programming/Integer Partition/code.js index 394753ef..0a4f969b 100644 --- a/Dynamic Programming/Integer Partition/code.js +++ b/Dynamic Programming/Integer Partition/code.js @@ -3,7 +3,7 @@ const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); -const integer = new Randomize.Integer(5, 14).create(); +const integer = Randomize.Integer({ min: 5, max: 14 }); const D = []; const A = []; for (let i = 0; i <= integer; i++) { diff --git a/Dynamic Programming/Longest Increasing Subsequence/code.js b/Dynamic Programming/Longest Increasing Subsequence/code.js index 1d80fc81..cfc13fc0 100644 --- a/Dynamic Programming/Longest Increasing Subsequence/code.js +++ b/Dynamic Programming/Longest Increasing Subsequence/code.js @@ -3,7 +3,7 @@ const { Tracer, Array1DTracer, LogTracer, Randomize, Layout, VerticalLayout } = const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); -const A = new Randomize.Array1D(10, new Randomize.Integer(0, 10)).create(); +const A = Randomize.Array1D({ N: 10, value: () => Randomize.Integer({ min: 0, max: 10 }) }); const LIS = new Array(A.length); tracer.set(A); Tracer.delay(); diff --git a/Dynamic Programming/Longest Palindromic Subsequence/code.js b/Dynamic Programming/Longest Palindromic Subsequence/code.js index db55f763..42b67224 100644 --- a/Dynamic Programming/Longest Palindromic Subsequence/code.js +++ b/Dynamic Programming/Longest Palindromic Subsequence/code.js @@ -30,6 +30,7 @@ function max(a, b) { } return b; } + logger.println('LPS for any string with length = 1 is 1'); for (i = 2; i <= N; i++) { logger.println('--------------------------------------------------'); diff --git a/Dynamic Programming/Maximum Sum Path/code.js b/Dynamic Programming/Maximum Sum Path/code.js index 8ff4f3e6..6a267ae1 100644 --- a/Dynamic Programming/Maximum Sum Path/code.js +++ b/Dynamic Programming/Maximum Sum Path/code.js @@ -1,6 +1,6 @@ const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); -const D = new Randomize.Array2D(5, 5, new Randomize.Integer(1, 5)).create(); +const D = Randomize.Array2D({ N: 5, M: 5, value: () => Randomize.Integer({ min: 1, max: 5 }) }); const dataViewer = new Array2DTracer(); const tracer = new Array2DTracer('Results Table'); const logger = new LogTracer(); diff --git a/Dynamic Programming/Sliding Window/code.js b/Dynamic Programming/Sliding Window/code.js index 01de463e..60d7212c 100644 --- a/Dynamic Programming/Sliding Window/code.js +++ b/Dynamic Programming/Sliding Window/code.js @@ -3,7 +3,7 @@ const { Tracer, Array1DTracer, LogTracer, Randomize, Layout, VerticalLayout } = const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); -const D = new Randomize.Array1D(20, new Randomize.Integer(-5, 5)).create(); +const D = Randomize.Array1D({ N: 20, value: () => Randomize.Integer({ min: -5, max: 5 }) }); tracer.set(D); Tracer.delay(); diff --git a/Dynamic Programming/Z String Search/code.js b/Dynamic Programming/Z String Search/code.js index a2e1b34b..b76cf622 100644 --- a/Dynamic Programming/Z String Search/code.js +++ b/Dynamic Programming/Z String Search/code.js @@ -39,7 +39,7 @@ function createZarr(concat) { concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is equal to ${concat[right - left]} (at index ${right - left})`); -Tracer.delay(); + Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); right++; @@ -48,7 +48,7 @@ Tracer.delay(); concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is NOT equal to ${concat[right - left]} (at index ${right - left})`); -Tracer.delay(); + Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); } @@ -72,7 +72,7 @@ Tracer.delay(); concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is equal to ${concat[right - left]} (at index ${right - left})`); -Tracer.delay(); + Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); right++; @@ -81,7 +81,7 @@ Tracer.delay(); concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is NOT equal to ${concat[right - left]} (at index ${right - left})`); -Tracer.delay(); + Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); } diff --git a/Greedy/Dijkstra's Shortest Path/code.js b/Greedy/Dijkstra's Shortest Path/code.js index 230d79de..d0a57ad9 100644 --- a/Greedy/Dijkstra's Shortest Path/code.js +++ b/Greedy/Dijkstra's Shortest Path/code.js @@ -5,7 +5,7 @@ const tracerS = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, tracerS, logger])); tracer.log(logger); -const G = new Randomize.Graph(5, 1).directed(false).weighted().create(); +const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); const MAX_VALUE = Infinity; const S = []; // S[end] returns the distance from start node to end node @@ -61,10 +61,10 @@ function Dijkstra(start, end) { } } -const s = new Randomize.Integer(0, G.length - 1).create(); // s = start node +const s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node let e; // e = end node do { - e = new Randomize.Integer(0, G.length - 1).create(); + e = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (s === e); logger.println(`finding the shortest path from ${s} to ${e}`); Tracer.delay(); diff --git a/Greedy/Kruskal's Minimum Spanning Tree/code.js b/Greedy/Kruskal's Minimum Spanning Tree/code.js index 51ab1360..77b9ff6a 100644 --- a/Greedy/Kruskal's Minimum Spanning Tree/code.js +++ b/Greedy/Kruskal's Minimum Spanning Tree/code.js @@ -10,7 +10,7 @@ Layout.setRoot(new VerticalLayout([tracer, logger])); [0, 2, 0, 0, 1], [0, 1, 3, 0, 0] ]; */ -const G = new Randomize.Graph(5, 1).directed(false).weighted().create(); +const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); diff --git a/Greedy/Prim's Minimum Spanning Tree/code.js b/Greedy/Prim's Minimum Spanning Tree/code.js index e3479538..e44458fc 100644 --- a/Greedy/Prim's Minimum Spanning Tree/code.js +++ b/Greedy/Prim's Minimum Spanning Tree/code.js @@ -11,7 +11,7 @@ tracer.log(logger); [0, 2, 0, 0, 1], [0, 1, 3, 0, 0] ]; */ -const G = new Randomize.Graph(10, .4).directed(false).weighted().create(); +const G = Randomize.Graph({ N: 10, ratio: .4, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); diff --git a/Greedy/Stable Matching/code.js b/Greedy/Stable Matching/code.js index 06886f76..1c15579e 100644 --- a/Greedy/Stable Matching/code.js +++ b/Greedy/Stable Matching/code.js @@ -68,9 +68,9 @@ while ((a = extractUnstable(A))) { b.stable = a; tracerA.select(_aKeys.indexOf(a.key)); -Tracer.delay(); + Tracer.delay(); tracerB.select(_bKeys.indexOf(b.key)); -Tracer.delay(); + Tracer.delay(); } else { const rankAinB = b.rankKeys.indexOf(a.key); const rankPrevAinB = b.rankKeys.indexOf(b.stable.key); @@ -80,15 +80,15 @@ Tracer.delay(); A[b.stable.key].stable = false; tracerA.deselect(_aKeys.indexOf(b.stable.key)); -Tracer.delay(); + Tracer.delay(); a.stable = b; b.stable = a; tracerA.select(_aKeys.indexOf(a.key)); -Tracer.delay(); + Tracer.delay(); tracerB.select(_bKeys.indexOf(b.key)); -Tracer.delay(); + Tracer.delay(); } } } diff --git a/Uncategorized/Affine Cipher/code.js b/Uncategorized/Affine Cipher/code.js index adcd087f..934b6f6e 100644 --- a/Uncategorized/Affine Cipher/code.js +++ b/Uncategorized/Affine Cipher/code.js @@ -45,7 +45,7 @@ function encrypt(plainText) { cypherText += cryptAlpha(plainText[i]); ptTracer.patch(i, cypherText.slice(-1)); -Tracer.delay(); + Tracer.delay(); ptTracer.depatch(i); } @@ -87,7 +87,7 @@ function decrypt(cypherText) { plainText += decryptAlpha(cypherText[i]); ctTracer.patch(i, plainText.slice(-1)); -Tracer.delay(); + Tracer.delay(); ctTracer.depatch(i); Tracer.delay(); } From e7dee5cc51c1fe2ce3cfeecbb71eb1457569e91c Mon Sep 17 00:00:00 2001 From: Jason Park Date: Fri, 14 Jun 2019 03:27:58 +0900 Subject: [PATCH 12/26] Add code validator and Travis CI --- .bin/batchFix.js | 45 ------- .gitignore | 2 - .travis.yml | 3 + .validate/constants.js | 9 ++ .validate/index.js | 32 +++++ .validate/js/index.js | 40 +++++++ .validate/utils.js | 24 ++++ README.md | 2 +- package-lock.json | 260 +++++++++++++++++++++++++++++++++++++++++ package.json | 12 ++ 10 files changed, 381 insertions(+), 48 deletions(-) delete mode 100644 .bin/batchFix.js create mode 100644 .travis.yml create mode 100644 .validate/constants.js create mode 100644 .validate/index.js create mode 100644 .validate/js/index.js create mode 100644 .validate/utils.js create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.bin/batchFix.js b/.bin/batchFix.js deleted file mode 100644 index fa047612..00000000 --- a/.bin/batchFix.js +++ /dev/null @@ -1,45 +0,0 @@ -const path = require('path'); -const fs = require('fs'); - -const isDirectory = dirPath => fs.lstatSync(dirPath).isDirectory(); -const listFiles = dirPath => fs.readdirSync(dirPath).filter(fileName => !fileName.startsWith('.')); -const listDirectories = dirPath => listFiles(dirPath).filter(fileName => isDirectory(path.resolve(dirPath, fileName))); - -const rootPath = path.resolve(__dirname, '..'); -listDirectories(rootPath).forEach(category => { - const categoryPath = path.resolve(rootPath, category); - listDirectories(categoryPath).forEach(algorithm => { - const algorithmPath = path.resolve(categoryPath, algorithm); - listFiles(algorithmPath).filter(file => /\.js$/.test(file)).forEach(file => { - const filePath = path.resolve(algorithmPath, file); - const content = fs.readFileSync(filePath, 'utf8'); - - /* - TODO: - 1. Break method chains (except for directed()/weighted()/layout*() - 2. Call static method delay() instead of member method delay() - */ - - const lines = content.split('\n'); - - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (line.includes('Randomize')) continue; - const match = /^(\s*)(\w+)(\.\w+\([^(]*\))(\.\w+\([^(]*\))(.+)$/.exec(line); - if (match) { - const [, first, variable, method1, method2, last] = match; - const firstLine = `${first}${variable}${method1};`; - const secondLine = `${first}${variable}${method2}${last}`; - lines.splice(i, 1, firstLine, secondLine); - } - } - - const newContent = lines.join('\n'); - if (newContent !== content) { - console.log(newContent); - console.log('------------------------------------------------------------'); - fs.writeFileSync(filePath, newContent, 'utf8'); - } - }); - }); -}); diff --git a/.gitignore b/.gitignore index a74e9a4e..ef887b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ /.idea /node_modules /npm-debug.log -/package.json -/package-lock.json .DS_Store diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..03e9faa1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: 'stable' +cache: npm diff --git a/.validate/constants.js b/.validate/constants.js new file mode 100644 index 00000000..f81a7969 --- /dev/null +++ b/.validate/constants.js @@ -0,0 +1,9 @@ +const path = require('path'); + +const rootDir = path.resolve(__dirname, '..'); +const MAX_STEPS = 100; + +module.exports = { + rootDir, + MAX_STEPS, +}; diff --git a/.validate/index.js b/.validate/index.js new file mode 100644 index 00000000..47231abc --- /dev/null +++ b/.validate/index.js @@ -0,0 +1,32 @@ +const path = require('path'); +const fs = require('fs-extra'); + +const { listDirectories, listFiles } = require('./utils'); +const { rootDir } = require('./constants'); +const validate = { + js: require('./js'), +}; + +const categories = listDirectories(rootDir).filter(dir => dir !== 'node_modules'); +let hasError = false; +for (const category of categories) { + const categoryDir = path.resolve(rootDir, category); + const algorithms = listDirectories(categoryDir); + for (const algorithm of algorithms) { + const algorithmDir = path.resolve(categoryDir, algorithm); + const files = listFiles(algorithmDir); + for (const file of files) { + const ext = file.split('.').pop(); + const validator = validate[ext]; + if (validator) { + const filePath = path.resolve(algorithmDir, file); + const content = fs.readFileSync(filePath, 'utf-8'); + if (!validator(category, algorithm, file, content)) { + hasError = true; + } + } + } + } +} + +process.exit(hasError ? 1 : 0); diff --git a/.validate/js/index.js b/.validate/js/index.js new file mode 100644 index 00000000..bef9740d --- /dev/null +++ b/.validate/js/index.js @@ -0,0 +1,40 @@ +const path = require('path'); +const { Commander } = require('algorithm-visualizer'); +const { rootDir } = require('../constants'); +const { signale } = require('../utils'); +const { MAX_STEPS } = require('../constants'); + +module.exports = (category, algorithm, file, content) => { + const errors = []; + const error = message => errors.push(message); + const warns = []; + const warn = message => warns.push(message); + + try { + Commander.init(); + require(path.resolve(rootDir, category, algorithm, file)); + } catch (e) { + error(e); + } + const steps = Commander.commands.filter(command => command.method === 'delay').length; + if (steps > MAX_STEPS) { + warn('Too many steps.'); + } + if (!/\/\/ import visualization libraries {/.test(content)) { + error('Missing the code folding for importing visualization libraries.'); + } + if (!/\/\/ define tracer variables {/.test(content)) { + error('Missing the code folding for defining tracer variables.'); + } + if (!/\/\/ visualize {/.test(content)) { + error('Missing the code folding for visualizing.'); + } + + if (errors.length || warns.length) { + signale.log(`${category}/${algorithm}/${file}`); + warns.forEach(error => signale.warn(error)); + errors.forEach(error => signale.error(error)); + signale.log(); + } + return errors.length === 0; +}; diff --git a/.validate/utils.js b/.validate/utils.js new file mode 100644 index 00000000..591afd85 --- /dev/null +++ b/.validate/utils.js @@ -0,0 +1,24 @@ +const path = require('path'); +const fs = require('fs-extra'); +const { Signale } = require('signale'); + +function isDirectory(dirPath) { + return fs.lstatSync(dirPath).isDirectory(); +} + +function listFiles(dirPath) { + return fs.pathExistsSync(dirPath) ? fs.readdirSync(dirPath).filter(fileName => !fileName.startsWith('.')) : []; +} + +function listDirectories(dirPath) { + return listFiles(dirPath).filter(fileName => isDirectory(path.resolve(dirPath, fileName))); +} + +const signale = new Signale(); + +module.exports = { + isDirectory, + listFiles, + listDirectories, + signale, +}; diff --git a/README.md b/README.md index 59a260a3..de35242c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Algorithms +# Algorithms [![Travis (.com)](https://img.shields.io/travis/com/algorithm-visualizer/algorithms.svg?style=flat-square)](https://travis-ci.com/algorithm-visualizer/algorithms) > This repository is part of the project [Algorithm Visualizer](https://github.com/algorithm-visualizer). diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..da6ea512 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,260 @@ +{ + "name": "algorithms-validator", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "algorithm-visualizer": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/algorithm-visualizer/-/algorithm-visualizer-2.3.5.tgz", + "integrity": "sha512-c1jJmJ1ba4qfDrWfW6TMWXs1mvj6uyUva2uhbNwg655r8/VXauvbXrYkF0E1j7JBTA2POep4Kl4AD1T/UKSuRA==", + "requires": { + "axios": "^0.18.0", + "opn": "^5.4.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "fs-extra": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.0.1.tgz", + "integrity": "sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "requires": { + "is-wsl": "^1.1.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + } + }, + "signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "requires": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..147e0d25 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "algorithms", + "version": "1.0.0", + "scripts": { + "test": "node .validate" + }, + "dependencies": { + "fs-extra": "^8.0.1", + "signale": "^1.4.0", + "algorithm-visualizer": "latest" + } +} From f2af23ad4dc676e2aeb0b347b1d48de90abd0517 Mon Sep 17 00:00:00 2001 From: Henry Lee Date: Mon, 8 Jul 2019 00:35:11 +1000 Subject: [PATCH 13/26] Modify the output in the Hamiltonean Cycles (#13) --- Backtracking/Hamiltonean Cycles/Code.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Backtracking/Hamiltonean Cycles/Code.java b/Backtracking/Hamiltonean Cycles/Code.java index 76c564cd..ad17c28e 100644 --- a/Backtracking/Hamiltonean Cycles/Code.java +++ b/Backtracking/Hamiltonean Cycles/Code.java @@ -75,7 +75,7 @@ void nextVal(int k) //} //Randomizing adjacancy matrix and displaying on log screen{ - logTracer.println("The adjacancy Matrix is"); + logTracer.println("The adjacancy matrix is"); for(int i=0;i Date: Wed, 16 Oct 2019 14:39:25 +0800 Subject: [PATCH 14/26] Improve Knuth-Morris-Pratt's String Search (#14) * Improve Knuth-Morris-Pratt's String Search The original code.js has both display and correctness errors. * Reconstruct Knuth-Morris-Pratt's String Search/code.js 1. Add code foldings 2. Delete log tracer to simplify the content 3. Delete redundant display steps 4. Indent using 4 spaces 5. Rename variables 6. Use fixed pattern and string to illustrate * Try to add code folding --- Backtracking/Knight's Tour Problem/code.js | 19 ++ Backtracking/N-Queens Problem/code.js | 22 +- .../Binary Search Tree/insertion.js | 17 ++ Branch and Bound/Binary Search Tree/search.js | 14 + Branch and Bound/Binary Search/iterative.js | 16 ++ Branch and Bound/Binary Search/recursive.js | 18 ++ Branch and Bound/Depth-Limited Search/code.js | 17 +- Branch and Bound/Topological Sort/code.js | 46 ++- Brute Force/Binary Tree Traversal/inOrder.js | 12 + .../Binary Tree Traversal/postOrder.js | 14 + Brute Force/Binary Tree Traversal/preOrder.js | 12 + Brute Force/Bipartiteness Test/code.js | 27 +- .../Breadth-First Search/shortestPath.js | 14 + Brute Force/Breadth-First Search/tree.js | 17 +- Brute Force/Bridge Finding/efficient.js | 36 ++- Brute Force/Bridge Finding/naive.js | 18 +- Brute Force/Bubble Sort/code.js | 20 ++ Brute Force/Comb Sort/code.js | 16 +- Brute Force/Cycle Sort/code.js | 24 ++ Brute Force/Depth-First Search/graph.js | 10 + .../Depth-First Search/shortestPath.js | 16 ++ Brute Force/Depth-First Search/tree.js | 15 +- .../Depth-First Search/weightedGraph.js | 10 + Brute Force/Flood Fill/code.js | 11 +- Brute Force/Heapsort/code.js | 14 + .../code.js | 272 ++++++++---------- 26 files changed, 545 insertions(+), 182 deletions(-) diff --git a/Backtracking/Knight's Tour Problem/code.js b/Backtracking/Knight's Tour Problem/code.js index ceeb7f62..e334bc8f 100644 --- a/Backtracking/Knight's Tour Problem/code.js +++ b/Backtracking/Knight's Tour Problem/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } /* For N>3 the time taken by this algorithm is sufficiently high @@ -26,6 +28,7 @@ const Y = [1, 2, 2, 1, -1, -2, -2, -1]; const pos = new Array(2); pos[0] = pos[1] = -1; +// define tracer variables { const boardTracer = new Array2DTracer('Board'); const posTracer = new Array1DTracer('Knight Position'); const logTracer = new LogTracer('Console'); @@ -33,6 +36,7 @@ boardTracer.set(board); posTracer.set(pos); Layout.setRoot(new VerticalLayout([boardTracer, posTracer, logTracer])); Tracer.delay(); +// } function knightTour(x, y, moveNum) { if (moveNum === N * N) { @@ -43,12 +47,14 @@ function knightTour(x, y, moveNum) { const nextX = x + X[i]; const nextY = y + Y[i]; + // visualize { posTracer.patch(0, nextX); Tracer.delay(); posTracer.patch(1, nextY); Tracer.delay(); posTracer.depatch(0); posTracer.depatch(1); + // } /* Check if knight is still in the board Check that knight does not visit an already visited square @@ -56,24 +62,33 @@ function knightTour(x, y, moveNum) { if (nextX >= 0 && nextX < N && nextY >= 0 && nextY < N && board[nextX][nextY] === -1) { board[nextX][nextY] = moveNum; + // visualize { logTracer.println(`Move to ${nextX},${nextY}`); boardTracer.patch(nextX, nextY, moveNum); Tracer.delay(); boardTracer.depatch(nextX, nextY); boardTracer.select(nextX, nextY); + // } const nextMoveNum = moveNum + 1; if (knightTour(nextX, nextY, nextMoveNum) === true) { return true; } + + // logger { logTracer.println(`No place to move from ${nextX},${nextY}: Backtrack`); + // } board[nextX][nextY] = -1; // backtrack + // visualize { boardTracer.patch(nextX, nextY, -1); Tracer.delay(); boardTracer.depatch(nextX, nextY); boardTracer.deselect(nextX, nextY); + // } } else { + // logger { logTracer.println(`${nextX},${nextY} is not a valid move`); + // } } } return false; @@ -83,6 +98,7 @@ board[0][0] = 0; // start from this position pos[0] = 0; pos[0] = 0; +// visualize { boardTracer.patch(0, 0, 0); Tracer.delay(); posTracer.patch(0, 0); @@ -93,9 +109,12 @@ boardTracer.depatch(0, 0); boardTracer.depatch(0, 0); posTracer.depatch(0); posTracer.depatch(1); +// } +// logger { if (knightTour(0, 0, 1) === false) { logTracer.println('Solution does not exist'); } else { logTracer.println('Solution found'); } +// } diff --git a/Backtracking/N-Queens Problem/code.js b/Backtracking/N-Queens Problem/code.js index 7812dd40..5f2e5b90 100644 --- a/Backtracking/N-Queens Problem/code.js +++ b/Backtracking/N-Queens Problem/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 4; // just change the value of N and the visuals will reflect the configuration! const board = (function createArray(N) { @@ -16,6 +18,7 @@ const queens = (function qSetup(N) { return result; }(N)); +// define tracer variables { const boardTracer = new Array2DTracer('Board'); const queenTracer = new Array2DTracer('Queen Positions'); const logger = new LogTracer('Progress'); @@ -25,6 +28,7 @@ boardTracer.set(board); queenTracer.set(queens); logger.println(`N Queens: ${N}X${N}matrix, ${N} queens`); Tracer.delay(); +// } function validState(row, col, currentQueen) { for (let q = 0; q < currentQueen; q++) { @@ -37,24 +41,31 @@ function validState(row, col, currentQueen) { } function nQ(currentQueen, currentCol) { + // logger { logger.println(`Starting new iteration of nQueens () with currentQueen = ${currentQueen} & currentCol = ${currentCol}`); logger.println('------------------------------------------------------------------'); + // } if (currentQueen >= N) { + // logger { logger.println('The recursion has BOTTOMED OUT. All queens have been placed successfully'); + // } return true; } let found = false; let row = 0; while ((row < N) && (!found)) { + // visualize { boardTracer.select(row, currentCol); Tracer.delay(); logger.println(`Trying queen ${currentQueen} at row ${row} & col ${currentCol}`); - + // } + if (validState(row, currentCol, currentQueen)) { queens[currentQueen][0] = row; queens[currentQueen][1] = currentCol; + // visualize { queenTracer.patch(currentQueen, 0, row); Tracer.delay(); queenTracer.patch(currentQueen, 1, currentCol); @@ -63,14 +74,17 @@ function nQ(currentQueen, currentCol) { Tracer.delay(); queenTracer.depatch(currentQueen, 1); Tracer.delay(); - + // } + found = nQ(currentQueen + 1, currentCol + 1); } if (!found) { + // visualize { boardTracer.deselect(row, currentCol); Tracer.delay(); logger.println(`row ${row} & col ${currentCol} didn't work out. Going down`); + // } } row++; } @@ -78,6 +92,10 @@ function nQ(currentQueen, currentCol) { return found; } +// logger { logger.println('Starting execution'); +// } nQ(0, 0); +// logger { logger.println('DONE'); +// } diff --git a/Branch and Bound/Binary Search Tree/insertion.js b/Branch and Bound/Binary Search Tree/insertion.js index a2656c45..f327b301 100644 --- a/Branch and Bound/Binary Search Tree/insertion.js +++ b/Branch and Bound/Binary Search Tree/insertion.js @@ -1,8 +1,12 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const T = {}; const elements = [5, 8, 10, 3, 1, 6, 9, 7, 2, 0, 4]; // item to be inserted + +// define tracer variables { const graphTracer = new GraphTracer(' BST - Elements marked red indicates the current status of tree '); const elemTracer = new Array1DTracer(' Elements '); const logger = new LogTracer(' Log '); @@ -10,10 +14,13 @@ Layout.setRoot(new VerticalLayout([graphTracer, elemTracer, logger])); elemTracer.set(elements); graphTracer.log(logger); Tracer.delay(); +// } function bstInsert(root, element, parent) { // root = current node , parent = previous node + // visualize { graphTracer.visit(root, parent); Tracer.delay(); + // } const treeNode = T[root]; let propName = ''; if (element < root) { @@ -25,30 +32,40 @@ function bstInsert(root, element, parent) { // root = current node , parent = pr if (!(propName in treeNode)) { // insert as left child of root treeNode[propName] = element; T[element] = {}; + // visualize { graphTracer.addNode(element); graphTracer.addEdge(root, element); graphTracer.select(element, root); Tracer.delay(); graphTracer.deselect(element, root); logger.println(`${element} Inserted`); + // } } else { bstInsert(treeNode[propName], element, root); } } + // visualize { graphTracer.leave(root, parent); Tracer.delay(); + // } } const Root = elements[0]; // take first element as root T[Root] = {}; +// visualize { graphTracer.addNode(Root); graphTracer.layoutTree(Root, true); logger.println(`${Root} Inserted as root of tree `); +// } for (let i = 1; i < elements.length; i++) { + // visualize { elemTracer.select(i); Tracer.delay(); + // } bstInsert(Root, elements[i]); // insert ith element + // visualize { elemTracer.deselect(i); Tracer.delay(); + // } } diff --git a/Branch and Bound/Binary Search Tree/search.js b/Branch and Bound/Binary Search Tree/search.js index f45f5f8a..0d9fdf0c 100644 --- a/Branch and Bound/Binary Search Tree/search.js +++ b/Branch and Bound/Binary Search Tree/search.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -29,6 +31,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ ]; const key = Randomize.Integer({ min: 0, max: G.length - 1 }); // item to be searched +// define tracer variables { const tracer = new GraphTracer(' Binary Search Tree '); const logger = new LogTracer(' Log '); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -36,26 +39,37 @@ tracer.set(G); tracer.layoutTree(5); tracer.log(logger); Tracer.delay(); +// } function bst(item, node, parent) { // node = current node , parent = previous node + // visualize { tracer.visit(node, parent); Tracer.delay(); + // } if (item === node) { // key found + // logger { logger.println(' Match Found '); + // } } else if (item < node) { // key less than value of current node if (T[node][0] === -1) { + // logger { logger.println(' Not Found '); + // } } else { bst(item, T[node][0], node); } } else { // key greater than value of current node if (T[node][1] === -1) { + // logger { logger.println(' Not Found '); + // } } else { bst(item, T[node][1], node); } } } +// logger { logger.println(`Finding number ${key}`); +// } bst(key, 5); // node with key 5 is the root diff --git a/Branch and Bound/Binary Search/iterative.js b/Branch and Bound/Binary Search/iterative.js index 5bb2d658..3fd3e005 100644 --- a/Branch and Bound/Binary Search/iterative.js +++ b/Branch and Bound/Binary Search/iterative.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,6 +11,7 @@ const D = Randomize.Array1D({ N: 15, value: () => Randomize.Integer({ min: 0, ma tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } function BinarySearch(array, element) { // array = sorted array, element = element to be found let minIndex = 0; @@ -18,6 +22,7 @@ function BinarySearch(array, element) { // array = sorted array, element = eleme const middleIndex = Math.floor((minIndex + maxIndex) / 2); testElement = array[middleIndex]; + // visualize { tracer.select(minIndex, maxIndex); Tracer.delay(); tracer.patch(middleIndex); @@ -25,26 +30,37 @@ function BinarySearch(array, element) { // array = sorted array, element = eleme Tracer.delay(); tracer.depatch(middleIndex); tracer.deselect(minIndex, maxIndex); + // } if (testElement < element) { + // logger { logger.println('Going right.'); + // } minIndex = middleIndex + 1; } else if (testElement > element) { + // logger { logger.println('Going left.'); + // } maxIndex = middleIndex - 1; } else { + // visualize { logger.println(`${element} is found at position ${middleIndex}!`); tracer.select(middleIndex); + // } return middleIndex; } } + // logger { logger.println(`${element} is not found!`); + // } return -1; } const element = D[Randomize.Integer({ min: 0, max: D.length - 1 })]; +// logger { logger.println(`Using iterative binary search to find ${element}`); +// } BinarySearch(D, element); diff --git a/Branch and Bound/Binary Search/recursive.js b/Branch and Bound/Binary Search/recursive.js index 2a20e61d..814e64ac 100644 --- a/Branch and Bound/Binary Search/recursive.js +++ b/Branch and Bound/Binary Search/recursive.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,16 +11,20 @@ const D = Randomize.Array1D({ N: 15, value: () => Randomize.Integer({ min: 0, ma tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } function BinarySearch(array, element, minIndex, maxIndex) { // array = sorted array, element = element to be found, minIndex = low index, maxIndex = high index if (minIndex > maxIndex) { + // logger { logger.println(`${element} is not found!`); + // } return -1; } const middleIndex = Math.floor((minIndex + maxIndex) / 2); const testElement = array[middleIndex]; + // visualize { tracer.select(minIndex, maxIndex); Tracer.delay(); tracer.patch(middleIndex); @@ -25,28 +32,39 @@ function BinarySearch(array, element, minIndex, maxIndex) { // array = sorted ar Tracer.delay(); tracer.depatch(middleIndex); tracer.deselect(minIndex, maxIndex); + // } if (testElement < element) { + // logger { logger.println('Going right.'); + // } return BinarySearch(array, element, middleIndex + 1, maxIndex); } if (testElement > element) { + // logger { logger.println('Going left.'); + // } return BinarySearch(array, element, minIndex, middleIndex - 1); } if (testElement === element) { + // visualize { logger.println(`${element} is found at position ${middleIndex}!`); tracer.select(middleIndex); + // } return middleIndex; } + // logger { logger.println(`${element} is not found!`); + // } return -1; } const element = D[Randomize.Integer({ min: 0, max: D.length - 1 })]; +// logger { logger.println(`Using binary search to find ${element}`); +// } BinarySearch(D, element, 0, D.length - 1); diff --git a/Branch and Bound/Depth-Limited Search/code.js b/Branch and Bound/Depth-Limited Search/code.js index b4f2530d..21709b93 100644 --- a/Branch and Bound/Depth-Limited Search/code.js +++ b/Branch and Bound/Depth-Limited Search/code.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); -tracer.log(logger); const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], @@ -17,15 +15,24 @@ const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); +tracer.log(logger); tracer.set(G); tracer.layoutTree(0); Tracer.delay(); +// } // This is a sample DLS applications where // we try to find number of descendant of root within some depth function DLSCount(limit, node, parent) { // node = current node, parent = previous node + // visualize { tracer.visit(node, parent); Tracer.delay(); + // } let child = 0; if (limit > 0) { // cut off the search for (let i = 0; i < G[node].length; i++) { @@ -38,4 +45,6 @@ function DLSCount(limit, node, parent) { // node = current node, parent = previo return child; } +// logger { logger.println(`Number of descendant is ${DLSCount(2, 0)}`); +// } diff --git a/Branch and Bound/Topological Sort/code.js b/Branch and Bound/Topological Sort/code.js index e55b7124..9f08909b 100644 --- a/Branch and Bound/Topological Sort/code.js +++ b/Branch and Bound/Topological Sort/code.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); -tracer.log(logger); // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not. NOTE: The graph must be Directed-Acyclic const G = [ [0, 0, 0, 0, 0, 0], @@ -13,70 +11,108 @@ const G = [ [1, 0, 0, 1, 0, 0], [1, 1, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); +tracer.log(logger); tracer.set(G); Tracer.delay(); +// } const inDegrees = Array(...Array(G.length)).map(Number.prototype.valueOf, 0); // create an Array of G.length number of 0s const Q = []; let iter = 0; let i; +// logger { logger.println('Calculating in-degrees for each Node...'); +// } + for (let currNode = 0; currNode < G.length; currNode++) { for (let currNodeNeighbor = 0; currNodeNeighbor < G.length; currNodeNeighbor++) { if (G[currNode][currNodeNeighbor]) { + // visualize { logger.println(`${currNodeNeighbor} has an incoming edge from ${currNode}`); tracer.visit(currNodeNeighbor, currNode); Tracer.delay(); + // } inDegrees[currNodeNeighbor]++; + // visualize { tracer.leave(currNodeNeighbor, currNode); Tracer.delay(); + // } } } } +// logger { logger.println(`Done. In-Degrees are: [ ${String(inDegrees)} ]`); logger.println(''); logger.println('Initializing queue with all the sources (nodes with no incoming edges)'); +// } inDegrees.map((indegrees, node) => { + // visualize { tracer.visit(node); Tracer.delay(); + // } if (!indegrees) { + // logger { logger.println(`${node} is a source`); + // } Q.push(node); } + // visualize { tracer.leave(node); Tracer.delay(); + // } }); +// logger { logger.println(`Done. Initial State of Queue: [ ${String(Q)} ]`); logger.println(''); +// } // begin topological sort (kahn) while (Q.length > 0) { + // logger { logger.println(`Iteration #${iter}. Queue state: [ ${String(Q)} ]`); + // } const currNode = Q.shift(); + // visualize { tracer.visit(currNode); Tracer.delay(); + // } for (i = 0; i < G.length; i++) { if (G[currNode][i]) { + // visualize { logger.println(`${i} has an incoming edge from ${currNode}. Decrementing ${i}'s in-degree by 1.`); tracer.visit(i, currNode); Tracer.delay(); + // } inDegrees[i]--; + // visualize { tracer.leave(i, currNode); Tracer.delay(); + // } if (!inDegrees[i]) { + // logger { logger.println(`${i}'s in-degree is now 0. Enqueuing ${i}`); + // } Q.push(i); } } } + // visualize { tracer.leave(currNode); Tracer.delay(); + // } + // logger { logger.println(`In-degrees are: [${String(inDegrees)} ]`); logger.println('-------------------------------------------------------------------'); - + // } + iter++; } diff --git a/Brute Force/Binary Tree Traversal/inOrder.js b/Brute Force/Binary Tree Traversal/inOrder.js index 8f8e26b2..1970212f 100644 --- a/Brute Force/Binary Tree Traversal/inOrder.js +++ b/Brute Force/Binary Tree Traversal/inOrder.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,6 +30,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer('Traversal In-order'); const arrayTracer = new Array1DTracer('Print In-order'); const logger = new LogTracer('Log'); @@ -36,24 +39,30 @@ treeTracer.set(G); treeTracer.layoutTree(5); arrayTracer.set(new Array(T.length).fill('-')); Tracer.delay(); +// } let index = 0; function inOrder(root, parent) { if (root === -1) { + // logger { logger.println('No more nodes. Backtracking.'); Tracer.delay(); + // } return; } + // visualize { logger.println(`Reached ${root}`); treeTracer.visit(root, parent); Tracer.delay(); logger.println(` Going left from ${root}`); Tracer.delay(); + // } inOrder(T[root][0], root); + // visualize { logger.println(`Printing ${root}`); treeTracer.leave(root); arrayTracer.patch(index++, root); @@ -61,8 +70,11 @@ function inOrder(root, parent) { logger.println(` Going right from ${root}`); Tracer.delay(); + // } inOrder(T[root][1], root); } inOrder(5); // node with key 5 is the root +// logger { logger.println('Finished'); +// } diff --git a/Brute Force/Binary Tree Traversal/postOrder.js b/Brute Force/Binary Tree Traversal/postOrder.js index e34b9752..c6da428b 100644 --- a/Brute Force/Binary Tree Traversal/postOrder.js +++ b/Brute Force/Binary Tree Traversal/postOrder.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,6 +30,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer('Traversal Post-order'); const arrayTracer = new Array1DTracer('Print Post-order'); const logger = new LogTracer('Log'); @@ -36,33 +39,44 @@ treeTracer.set(G); treeTracer.layoutTree(5); arrayTracer.set(new Array(T.length).fill('-')); Tracer.delay(); +// } let index = 0; function postOrder(root, parent) { if (root === -1) { + // logger { logger.println('No more nodes. Backtracking.'); Tracer.delay(); + // } return; } + // visualize { logger.println(`Reached ${root}`); treeTracer.visit(root, parent); Tracer.delay(); logger.println(` Going left from ${root}`); Tracer.delay(); + // } postOrder(T[root][0], root); + // logger { logger.println(` Going right from ${root}`); Tracer.delay(); + // } postOrder(T[root][1], root); + // visualize { logger.println(`Printing ${root}`); treeTracer.leave(root); arrayTracer.patch(index++, root); Tracer.delay(); + // } } postOrder(5); // node with key 5 is the root +// logger { logger.println('Finished'); +// visualize { diff --git a/Brute Force/Binary Tree Traversal/preOrder.js b/Brute Force/Binary Tree Traversal/preOrder.js index 67c110b2..ccd0f4b5 100644 --- a/Brute Force/Binary Tree Traversal/preOrder.js +++ b/Brute Force/Binary Tree Traversal/preOrder.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,6 +30,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer('Traversal Pre-order'); const arrayTracer = new Array1DTracer('Print Pre-order'); const logger = new LogTracer('Log'); @@ -36,16 +39,20 @@ treeTracer.set(G); treeTracer.layoutTree(5); arrayTracer.set(new Array(T.length).fill('-')); Tracer.delay(); +// } let index = 0; function preOrder(root, parent) { if (root === -1) { + // logger { logger.println('No more nodes. Backtracking.'); Tracer.delay(); + // } return; } + // visualize { logger.println(`Reached ${root}`); treeTracer.visit(root, parent); Tracer.delay(); @@ -57,12 +64,17 @@ function preOrder(root, parent) { logger.println(` Going left from ${root}`); Tracer.delay(); + // } preOrder(T[root][0], root); + // logger { logger.println(` Going right from ${root}`); Tracer.delay(); + // } preOrder(T[root][1], root); } preOrder(5); // node with key 5 is the root +// logger { logger.println('Finished'); +// } diff --git a/Brute Force/Bipartiteness Test/code.js b/Brute Force/Bipartiteness Test/code.js index 3e36f342..62d4e4ec 100644 --- a/Brute Force/Bipartiteness Test/code.js +++ b/Brute Force/Bipartiteness Test/code.js @@ -1,8 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); - -const tracer = new GraphTracer().directed(false); -const logger = new LogTracer(); -tracer.log(logger); +// } const G = [ [0, 1, 0, 1, 1], @@ -11,11 +9,16 @@ const G = [ [1, 0, 1, 0, 0], // <-- replace latest 0 with 1 to make G not biparted [1, 0, 0, 0, 0], ]; -tracer.set(G); +// define tracer variables { +const tracer = new GraphTracer().directed(false); +const logger = new LogTracer(); +tracer.log(logger); +tracer.set(G); const colorsTracer = new Array1DTracer('Colors'); Layout.setRoot(new VerticalLayout([tracer, logger, colorsTracer])); Tracer.delay(); +// } function BFSCheckBipartiteness(s) { const Q = []; @@ -23,36 +26,50 @@ function BFSCheckBipartiteness(s) { // Create a new matrix to set colors (0,1) const Colors = []; for (let _i = 0; _i < G.length; _i++) Colors[_i] = -1; + // visualize { colorsTracer.set(Colors); + // } Colors[s] = 1; + // visualize { colorsTracer.patch(s, 1); + // } Q.push(s); // add start node to queue while (Q.length > 0) { const node = Q.shift(); // dequeue + // visualize { tracer.visit(node); Tracer.delay(); + // } for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { if (Colors[i] === -1) { Colors[i] = 1 - Colors[node]; + // visualize { colorsTracer.patch(i, 1 - Colors[node]); + // } Q.push(i); + // visualize { tracer.visit(i, node); Tracer.delay(); + // } } else if (Colors[i] === Colors[node]) { + // logger { logger.println('Graph is not biparted'); + // } return false; } } } } + // logger { logger.println('Graph is biparted'); + // } return true; } diff --git a/Brute Force/Breadth-First Search/shortestPath.js b/Brute Force/Breadth-First Search/shortestPath.js index bee38433..0875ad82 100644 --- a/Brute Force/Breadth-First Search/shortestPath.js +++ b/Brute Force/Breadth-First Search/shortestPath.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,6 +10,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function BFS() { const W = []; // W[i] indicates the length of the shortest path from start node to the i-th node @@ -14,12 +18,16 @@ function BFS() { let i; for (i = 0; i < G.length; i++) { W.push(MAX_VALUE); + // visualize { tracer.updateNode(i, MAX_VALUE); + // } } W[s] = 0; Q.push(s); // add start node to queue + // visualize { tracer.visit(s, undefined, 0); Tracer.delay(); + // } while (Q.length > 0) { const node = Q.shift(); // dequeue for (i = 0; i < G[node].length; i++) { @@ -27,8 +35,10 @@ function BFS() { if (W[i] > W[node] + G[node][i]) { // if current path is shorter than the previously shortest path W[i] = W[node] + G[node][i]; // update the length of the shortest path Q.push(i); // add child node to queue + // visualize { tracer.visit(i, node, W[i]); Tracer.delay(); + // } } } } @@ -42,10 +52,14 @@ do { e = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (s === e); let MAX_VALUE = 0x7fffffff; +// logger { logger.println(`finding the shortest path from ${s} to ${e}`); +// } const minWeight = BFS(s); +// logger { if (minWeight === MAX_VALUE) { logger.println(`there is no path from ${s} to ${e}`); } else { logger.println(`the shortest path from ${s} to ${e} is ${minWeight}`); } +// } diff --git a/Brute Force/Breadth-First Search/tree.js b/Brute Force/Breadth-First Search/tree.js index 598a7dd1..f2c8411b 100644 --- a/Brute Force/Breadth-First Search/tree.js +++ b/Brute Force/Breadth-First Search/tree.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -tracer.log(logger); -Layout.setRoot(new VerticalLayout([tracer, logger])); const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], @@ -17,22 +15,33 @@ const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +tracer.log(logger); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); tracer.layoutTree(0); Tracer.delay(); +// } function BFS(s) { // s = start node const Q = []; Q.push(s); // add start node to queue + // visualize { tracer.visit(s); Tracer.delay(); + // } while (Q.length > 0) { const node = Q.shift(); // dequeue for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if current node has the i-th node as a child Q.push(i); // add child node to queue + // visualize { tracer.visit(i, node); Tracer.delay(); + // } } } } diff --git a/Brute Force/Bridge Finding/efficient.js b/Brute Force/Bridge Finding/efficient.js index a9c05b83..9864d2b2 100644 --- a/Brute Force/Bridge Finding/efficient.js +++ b/Brute Force/Bridge Finding/efficient.js @@ -1,8 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const graphTracer = new GraphTracer().directed(false); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([graphTracer, logger])); const G = [ [0, 1, 0, 0, 1, 0], [1, 0, 0, 0, 1, 0], @@ -12,8 +11,13 @@ const G = [ [0, 0, 0, 1, 0, 0], ]; +// define tracer variables { +const graphTracer = new GraphTracer().directed(false); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([graphTracer, logger])); graphTracer.set(G); Tracer.delay(); +// } /* NOTE: Code assumes NO parallel edges @@ -29,56 +33,74 @@ const util = (u, disc, low, parent) => { // disc is the numbering of the vertices in the DFS, starting at 0 // low[v] is the lowest numbered vertex that can be reached from vertex v along the DFS // parent is the node that u came from + // visualize { logger.println(''); logger.println(`Visiting node ${u}`); graphTracer.visit(u); Tracer.delay(); graphTracer.leave(u); Tracer.delay(); + // } // visited [u] = true; disc[u] = low[u] = timer++; + // logger { logger.println(`Nodes adjacent to ${u} are: [ ${adj[u]} ]`); + // } /* adj [u].forEach (function (v) { graphTracer.visit (v, u).delay (); graphTracer.leave (v, u).delay (); }); */ const trace = (v) => { + // visualize { graphTracer.visit(v, u); Tracer.delay(); graphTracer.leave(v, u); Tracer.delay(); + // } }; adj[u].forEach((v) => { if (disc[v] > -1 && v === parent) { trace(v); + // logger { logger.println(`${u}'s neighbor ${v} is u's parent. Not visiting it.`); + // } } else if (disc[v] > -1 && v !== parent) { trace(v); + // logger { logger.println(`${u}'s neighbor ${v} is not u's parent. Comparing low[u] with disc[v]`); + // } if (low[u] > disc[v]) { + // logger { logger.println(`low[${u}] is greater than disc[${v}]. Setting low[${u}] to disc[${v}]`); + // } low[u] = disc[v]; } } if (disc[v] === -1) { trace(v); + // logger { logger.println(`${u}'s neighbor ${v} has not been visited yet`); logger.println(`recursively calling util (${v}, [${disc}], [${low}],${u})`); + // } util(v, disc, low, u); + // logger { logger.println('--------------------------------------------------------------------'); logger.println(`Setting low [${u}] to ${Math.min(low[u], low[v])}`); + // } low[u] = Math.min(low[u], low[v]); if (low[v] === disc[v]) { + // logger { logger.println(`low [${v}] === disc [${v}], low[${v}]=${low[v]}, disc[${v}]=${disc[v]}`); logger.println(`${u} -> ${v} is a bridge. Adding ${u}->${v}to the set of bridges found`); + // } bridges.push([u, v]); } } @@ -104,6 +126,7 @@ const util = (u, disc, low, parent) => { }); }()); + // logger { logger.println(`Initializing: disc: ${disc} low: ${low}`); logger.println(''); logger.println('Beginning efficient Bridge Finding'); @@ -111,17 +134,24 @@ const util = (u, disc, low, parent) => { logger.println(''); logger.println('Starting the main for loop (for each node)'); + // } for (let v = 0; v < graph.length; v++) { if (disc[v] === -1) { + // logger { logger.println(`${v} has not been visited yet. Calling util (${v}, [${disc}], [${low}],${v}) from the for loop`); + // } util(v, disc, low, v); + // logger { logger.println(`Returned in for loop after util (${v}, [${disc}], [${low}], [${v}])`); + // } } } }(G)); +// logger { logger.println(`There are ${bridges.length} bridges in the Graph`); for (let i = 0; i < bridges.length; i++) { logger.println(`${bridges[i][0]}-->${bridges[i][1]}`); } logger.println('NOTE: All bridges are both ways (just like in the Naive Algorithm) because the Graph is undirected. So, edge A->B and B->A, both are bridges'); +// } diff --git a/Brute Force/Bridge Finding/naive.js b/Brute Force/Bridge Finding/naive.js index c8ab7d14..4dd4233b 100644 --- a/Brute Force/Bridge Finding/naive.js +++ b/Brute Force/Bridge Finding/naive.js @@ -1,8 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer().directed(false); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); const G = [ [0, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 0], @@ -12,8 +11,13 @@ const G = [ [0, 0, 0, 1, 0, 0], ]; +// define tracer variables { +const tracer = new GraphTracer().directed(false); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); Tracer.delay(); +// } // Depth First Search Exploration Algorithm to test connectedness of the Graph (see Graph Algorithms/DFS/exploration), without the tracer & logger commands function DFSExplore(graph, source) { @@ -51,11 +55,13 @@ function findBridges(graph) { for (let i = 0; i < graph.length; i++) { for (let j = 0; j < graph.length; j++) { if (graph[i][j]) { // check if an edge exists + // visualize { logger.println(`Deleting edge ${i}->${j} and calling DFSExplore ()`); tracer.visit(j, i); Tracer.delay(); tracer.leave(j, i); Tracer.delay(); + // } tempGraph = JSON.parse(JSON.stringify(graph)); tempGraph[i][j] = 0; @@ -63,9 +69,13 @@ function findBridges(graph) { visited = DFSExplore(tempGraph, 0); if (Object.keys(visited).length === graph.length) { + // logger { logger.println('Graph is CONNECTED. Edge is NOT a bridge'); + // } } else { + // logger { logger.println('Graph is DISCONNECTED. Edge IS a bridge'); + // } bridges.push([i, j]); } } @@ -77,8 +87,10 @@ function findBridges(graph) { const bridges = findBridges(G); +// logger { logger.println('The bridges are: '); for (const i in bridges) { logger.println(`${bridges[i][0]} to ${bridges[i][1]}`); } logger.println('NOTE: A bridge is both ways, i.e., from A to B and from B to A, because this is an Undirected Graph'); +// } diff --git a/Brute Force/Bubble Sort/code.js b/Brute Force/Bubble Sort/code.js index 136f7c97..a69ae686 100644 --- a/Brute Force/Bubble Sort/code.js +++ b/Brute Force/Bubble Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,32 +11,49 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } let N = D.length; let swapped; do { swapped = false; + // visualize { tracer.select(N - 1); Tracer.delay(); + // } for (let i = 1; i < N; i++) { + // visualize { tracer.select(i); Tracer.delay(); + // } if (D[i - 1] > D[i]) { + // logger { logger.println(`swap ${D[i - 1]} and ${D[i]}`); + // } const temp = D[i - 1]; D[i - 1] = D[i]; D[i] = temp; swapped = true; + // visualize { tracer.patch(i - 1, D[i - 1]); tracer.patch(i, D[i]); Tracer.delay(); tracer.depatch(i - 1); tracer.depatch(i); + // } } + // visualize { tracer.deselect(i); + // } } + // visualize { tracer.deselect(N - 1); + // } N--; } while (swapped); +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Comb Sort/code.js b/Brute Force/Comb Sort/code.js index fbbdbf89..6d3bc2ae 100644 --- a/Brute Force/Comb Sort/code.js +++ b/Brute Force/Comb Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } const N = D.length; let swapped; let gap = N; // initialize gap size @@ -26,26 +32,34 @@ do { swapped = false; // initialize swapped // a single comb over the input list for (let i = 0; i + gap < N; i++) { + // visualize { tracer.select(i); tracer.select(i + gap); Tracer.delay(); + // } if (D[i] > D[i + gap]) { + // logger { logger.println(`swap ${D[i]} and ${D[i + gap]}`); // log swap event - + // } + const temp = D[i]; D[i] = D[i + gap]; D[i + gap] = temp; + // visualize { tracer.patch(i, D[i]); tracer.patch(i + gap, D[i + gap]); Tracer.delay(); tracer.depatch(i); tracer.depatch(i + gap); + // } swapped = true; // Flag swapped has happened and list is not guaranteed sorted } + // visualize { tracer.deselect(i); tracer.deselect(i + gap); + // } } // End of combing } while (gap !== 1 || swapped); diff --git a/Brute Force/Cycle Sort/code.js b/Brute Force/Cycle Sort/code.js index 8bc185d2..9dac822a 100644 --- a/Brute Force/Cycle Sort/code.js +++ b/Brute Force/Cycle Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } const N = D.length; let writes = 0; // number of writing performed let pos; // the index of item in the sorted array @@ -20,12 +26,16 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { // find where to put the item pos = cycleStart; + // visualize { tracer.select(cycleStart); + // } for (let i = cycleStart + 1; i <= N - 1; i++) { + // visualize { tracer.select(i); Tracer.delay(); tracer.deselect(i); + // } if (D[i] < item) { pos++; } @@ -33,7 +43,9 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { // if the item is already there, this is not a circle if (pos === cycleStart) { + // visualize { tracer.deselect(cycleStart); + // } continue; } @@ -49,11 +61,14 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { writes++; + // logger { if (pos !== cycleStart) { logger.println(`Rewrite ${D[pos]} to index ${pos}; the next value to rewrite is ${item}`); } else { logger.println(`Rewrite ${D[pos]} to index ${pos}`); } + // } + // visualize { tracer.select(pos); Tracer.delay(); tracer.deselect(pos); @@ -62,15 +77,18 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { Tracer.delay(); tracer.depatch(pos); tracer.depatch(cycleStart); + // } // rotate the rest of the cycle while (pos !== cycleStart) { pos = cycleStart; for (let i = cycleStart + 1; i <= N - 1; i++) { + // visualize { tracer.select(i); Tracer.delay(); tracer.deselect(i); + // } if (D[i] < item) { pos++; } @@ -84,11 +102,14 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { D[pos] = item; item = temp; + // logger { if (pos !== cycleStart) { logger.println(`Rewrite ${D[pos]} to index ${pos}; the next value to rewrite is ${item}`); } else { logger.println(`Rewrite ${D[pos]} to index ${pos}`); } + // } + // visualize { tracer.select(pos); Tracer.delay(); tracer.deselect(pos); @@ -97,9 +118,12 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { Tracer.delay(); tracer.depatch(pos); tracer.depatch(cycleStart); + // } writes++; } } +// logger { logger.println(`Number of writes performed is ${writes}`); +// } diff --git a/Brute Force/Depth-First Search/graph.js b/Brute Force/Depth-First Search/graph.js index eb7881de..07660a77 100644 --- a/Brute Force/Depth-First Search/graph.js +++ b/Brute Force/Depth-First Search/graph.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const graphTracer = new GraphTracer().directed(false); const visitedTracer = new Array1DTracer('visited'); const logger = new LogTracer(); @@ -8,6 +11,7 @@ graphTracer.log(logger); const G = Randomize.Graph({ N: 8, ratio: .3, directed: false }); graphTracer.set(G); Tracer.delay(); +// } function DFSExplore(graph, source) { const stack = [[source, null]]; @@ -19,7 +23,9 @@ function DFSExplore(graph, source) { for (i = 0; i < graph.length; i++) { visited.push(false); } + // visualize { visitedTracer.set(visited); + // } while (stack.length > 0) { temp = stack.pop(); @@ -28,6 +34,7 @@ function DFSExplore(graph, source) { if (!visited[node]) { visited[node] = true; + // visualize { visitedTracer.patch(node, visited[node]); if (prev !== undefined && graph[node][prev]) { @@ -37,6 +44,7 @@ function DFSExplore(graph, source) { graphTracer.visit(node); Tracer.delay(); } + // } for (i = 0; i < graph.length; i++) { if (graph[node][i]) { @@ -52,8 +60,10 @@ function DFSExplore(graph, source) { const visited = DFSExplore(G, 0); let check = true; for (let i = 0; i < visited.length; i++) check &= visited[i]; +// logger { if (check) { logger.println('The Graph is CONNECTED'); } else { logger.println('The Graph is NOT CONNECTED'); } +// } diff --git a/Brute Force/Depth-First Search/shortestPath.js b/Brute Force/Depth-First Search/shortestPath.js index 9403fc24..646b865c 100644 --- a/Brute Force/Depth-First Search/shortestPath.js +++ b/Brute Force/Depth-First Search/shortestPath.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,22 +10,29 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function DFS(node, parent, weight) { // node = current node, parent = previous node if (minWeight < weight) return; if (node === e) { + // visualize { tracer.visit(node, parent, weight); Tracer.delay(); + // } if (minWeight > weight) { minWeight = weight; } + // visualize { tracer.leave(node, parent, minWeight); Tracer.delay(); + // } return; } D[node] = true; // label current node as discovered + // visualize { tracer.visit(node, parent, weight); Tracer.delay(); + // } for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if the path from current node to the i-th node exists if (!D[i]) { // if the i-th node is not labeled as discovered @@ -31,8 +41,10 @@ function DFS(node, parent, weight) { // node = current node, parent = previous n } } D[node] = false; // label current node as undiscovered + // visualize { tracer.leave(node, parent, 0); Tracer.delay(); + // } } const s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node @@ -42,12 +54,16 @@ do { } while (s === e); const MAX_VALUE = Infinity; let minWeight = MAX_VALUE; +// logger { logger.println(`finding the shortest path from ${s} to ${e}`); +// } let D = []; // D[i] indicates whether the i-th node is discovered or not for (let i = 0; i < G.length; i++) D.push(false); DFS(s, undefined, 0); +// logger { if (minWeight === MAX_VALUE) { logger.println(`there is no path from ${s} to ${e}`); } else { logger.println(`the shortest path from ${s} to ${e} is ${minWeight}`); } +// } diff --git a/Brute Force/Depth-First Search/tree.js b/Brute Force/Depth-First Search/tree.js index 4d9a3508..a582c529 100644 --- a/Brute Force/Depth-First Search/tree.js +++ b/Brute Force/Depth-First Search/tree.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -tracer.log(logger); -Layout.setRoot(new VerticalLayout([tracer, logger])); const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], @@ -17,13 +15,22 @@ const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +tracer.log(logger); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); tracer.layoutTree(0); Tracer.delay(); +// } function DFS(node, parent) { // node = current node, parent = previous node + // visualize {/ tracer.visit(node, parent); Tracer.delay(); + // } for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if current node has the i-th node as a child DFS(i, node); // recursively call DFS diff --git a/Brute Force/Depth-First Search/weightedGraph.js b/Brute Force/Depth-First Search/weightedGraph.js index c71549af..b57b1f0b 100644 --- a/Brute Force/Depth-First Search/weightedGraph.js +++ b/Brute Force/Depth-First Search/weightedGraph.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,12 +10,15 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } let D; // D[i] indicates whether the i-th node is discovered or not function DFS(node, parent, weight) { // node = current node, parent = previous node + // visualize { tracer.visit(node, parent, weight); Tracer.delay(); + // } D[node] = true; // label current node as discovered for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if the edge from current node to the i-th node exists @@ -22,12 +28,16 @@ function DFS(node, parent, weight) { // node = current node, parent = previous n } } D[node] = false; // label current node as undiscovered + // visualize { tracer.leave(node, parent, 0); Tracer.delay(); + // } } for (let i = 0; i < G.length; i++) { // start from every node + // logger { logger.println(`start from ${i}`); + // } D = []; for (let j = 0; j < G.length; j++) D.push(false); DFS(i, undefined, 0); diff --git a/Brute Force/Flood Fill/code.js b/Brute Force/Flood Fill/code.js index f6b17a26..316b5fff 100644 --- a/Brute Force/Flood Fill/code.js +++ b/Brute Force/Flood Fill/code.js @@ -1,7 +1,7 @@ +// import visualization libraries { const { Tracer, Array2DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array2DTracer(); -Layout.setRoot(new VerticalLayout([tracer])); const G = [ ['#', '#', '#', '#', '#', '#', '#', '#', '#'], ['#', '-', '-', '-', '#', '-', '-', '-', '#'], @@ -13,8 +13,13 @@ const G = [ ['#', '-', '-', '-', '#', '-', '-', '-', '#'], ['#', '#', '#', '#', '#', '#', '#', '#', '#'], ]; + +// define tracer variables { +const tracer = new Array2DTracer(); +Layout.setRoot(new VerticalLayout([tracer])); tracer.set(G); Tracer.delay(); +// } function FloodFill(i, j, oldColor, newColor) { if (i < 0 || i >= G.length || j < 0 || j >= G[i].length) return; @@ -23,10 +28,12 @@ function FloodFill(i, j, oldColor, newColor) { // set the color of node to newColor G[i][j] = newColor; + // visualize { tracer.select(i, j); Tracer.delay(); tracer.patch(i, j, G[i][j]); Tracer.delay(); + // } // next step four-way FloodFill(i + 1, j, oldColor, newColor); diff --git a/Brute Force/Heapsort/code.js b/Brute Force/Heapsort/code.js index 73832cb8..d0abb120 100644 --- a/Brute Force/Heapsort/code.js +++ b/Brute Force/Heapsort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 10 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`Original array = [${D.join(', ')}]`); +// } function heapSort(array, size) { let i; @@ -25,6 +31,7 @@ function heapSort(array, size) { array[0] = array[j]; array[j] = temp; + // visualize { tracer.patch(0, array[0]); tracer.patch(j, array[j]); logger.println(`Swapping elements : ${array[0]} & ${array[j]}`); @@ -33,10 +40,13 @@ function heapSort(array, size) { tracer.depatch(j); tracer.select(j); Tracer.delay(); + // } heapify(array, j, 0); + // visualize { tracer.deselect(j); + // } } } @@ -59,12 +69,14 @@ function heapify(array, size, root) { array[root] = array[largest]; array[largest] = temp; + // visualize { tracer.patch(root, array[root]); tracer.patch(largest, array[largest]); logger.println(`Swapping elements : ${array[root]} & ${array[largest]}`); Tracer.delay(); tracer.depatch(root); tracer.depatch(largest); + // } heapify(array, size, largest); } @@ -72,4 +84,6 @@ function heapify(array, size, root) { heapSort(D, D.length); +// logger { logger.println(`Final array = [${D.join(', ')}]`); +// } diff --git a/Dynamic Programming/Knuth-Morris-Pratt's String Search/code.js b/Dynamic Programming/Knuth-Morris-Pratt's String Search/code.js index ce1788fe..c19230a1 100644 --- a/Dynamic Programming/Knuth-Morris-Pratt's String Search/code.js +++ b/Dynamic Programming/Knuth-Morris-Pratt's String Search/code.js @@ -1,155 +1,129 @@ -const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); - -function randString(length) { - const result = Math.random().toString(36); - return result.substring(result.length - length); -} - -const string = randString(15); - -const startIndex = Math.floor(Math.random() * 10); // Random start index from 0 to 9 -const substring = string.substr(startIndex, 5); // Substring of `string` of length 5 - -// let string = 'abcxabcdabxabcdabcdabxabcda', substring = 'xabcda'; -// let string = 'abcxabcdabxabcdabcdabcyiuhsiuhduiahdubhbuuabcdabcysbhbh', substring = 'abcdabcy'; - -let track = Array(...Array(substring.length)).map(Number.prototype.valueOf, 0); - -const trackTracer = new Array1DTracer('Tracker'); -const substrTracer = new Array1DTracer('Substring'); -const stringTracer = new Array1DTracer('Major String'); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([trackTracer, substrTracer, stringTracer, logger])); - -trackTracer.set(track); -substrTracer.set(substring); -stringTracer.set(string); -Tracer.delay(); - -// Fix JS Negative number modulo Bug -Number.prototype.mod = function (n) { - return ((this % n) + n) % n; -}; - -function tracker(substring) { - let i = 1; - let j = 0; - - logger.println('Initializing i to 1, j to 0.'); - substrTracer.select(j); - while (i < track.length) { - substrTracer.select(i); - Tracer.delay(); - - while ((substring[i] !== substring[j]) && (j > 0)) { - logger.println(`j = ${track[j - 1]}`); - trackTracer.select(j - 1); - Tracer.delay(); - trackTracer.deselect(j - 1); - Tracer.delay(); - - substrTracer.deselect(j); - j = track[j - 1]; - logger.println(`j = ${j}`); - substrTracer.select(j); - } - - if (substring[i] === substring[j]) { - substrTracer.deselect(j); - track[i] = ++j; - trackTracer.patch(i, track[i]); - Tracer.delay(); - trackTracer.depatch(i); - Tracer.delay(); - logger.println(`substring [ ${i} ] (${substring[i]}) equals substring [ ${j} ] (${substring[j]}), track [ ${i} ] updated to: ${track[i]}`); - - logger.println(`j = ${j}`); - substrTracer.select(j); - } else { - track[i] = 0; - logger.println(`substring [ ${i} ] (${substring[i]}) is not equal to substring [ ${j} ] (${substring[j]}), setting track [${i}] to 0`); - trackTracer.select(i); - Tracer.delay(); - trackTracer.deselect(i); - Tracer.delay(); +// import visualization libraries { +const { Tracer, Array1DTracer, Array2DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +const string = "AAAABAABAAAABAAABAAAA"; +const pattern = "AAAABAAA"; + +let _next = Array(...Array(pattern.length)).map(Number.prototype.valueOf, 0); +// define tracer variables { +const pattern_tracer = new Array2DTracer('Pattern'); +const string_tracer = new Array1DTracer('String'); +Layout.setRoot(new VerticalLayout([pattern_tracer, string_tracer])); +pattern_tracer.set([_next, pattern, pattern]); +string_tracer.set(string); Tracer.delay(); +// } + +function get_next(pattern) +{ + let q = 1; // postfix pointer + let k = 0; // prefix pointer + // visualize { + pattern_tracer.select(2, k); + // } + for (; q < pattern.length; ++q) + { + // visualize { + pattern_tracer.select(1, q); Tracer.delay(); + // } + while ((k > 0) && (pattern[q] !== pattern[k])) + { + // visualize { + pattern_tracer.select(0, k - 1); Tracer.delay(); + pattern_tracer.deselect(2, k); + pattern_tracer.select(2, _next[k - 1]); Tracer.delay(); + pattern_tracer.deselect(0, k - 1); + // } + k = _next[k - 1]; + } + if (pattern[q] === pattern[k]) + { + // visualize { + pattern_tracer.deselect(2, k); + pattern_tracer.select(2, k + 1); Tracer.delay(); + // } + ++k; + } + // visualize { + pattern_tracer.patch(0, q, k); Tracer.delay(); + pattern_tracer.depatch(0, q); Tracer.delay(); + pattern_tracer.deselect(1, q); + // } + _next[q] = k; } - - substrTracer.deselect(i); - Tracer.delay(); - i++; - logger.println(`i = ${i}`); - } - - return track; + // visualize { + pattern_tracer.deselect(2, k); + pattern_tracer.set([_next, pattern]); Tracer.delay(); + // } } -function kmp(string, substr) { - const positions = []; - let j = 0; - let startPos; - - logger.println(`Constructing Tracker for substring ${substr}`); - track = tracker(substr); - logger.println(`Tracker for substring constructed: [ ${String(track)} ]`); - logger.println('--------------------------------------------------------------------------'); - logger.println('Running KMP...'); - - logger.println('Initializing i = 0, j = 0'); - for (let i = 0; i < string.length; i++) { - logger.println(`comparing string [${i}] (${string[i]}) and substring [${j}] (${substr[j]})...`); - stringTracer.select(i); - Tracer.delay(); - stringTracer.select(j); - Tracer.delay(); - - if (string[i] === substr[j]) { - logger.println('they\'re equal!'); - - if (j === substr.length - 1) { - logger.println(`j (${j}) equals length of substring - 1 (${substr.length}-1), we've found a new match in the string!`); - startPos = i - substr.length + 1; - positions.push(startPos); - - logger.println(`Adding start position of the substring (${startPos}) to the results.`); - stringTracer.select(startPos); - Tracer.delay(); - } else { - stringTracer.deselect(j); - Tracer.delay(); - logger.println(`But j (${j}) does not equal length of substring (${substr.length}) Incrementing j and moving forward.`); - j++; - logger.println(`j = ${j}`); - stringTracer.select(j); - Tracer.delay(); - } - } else { - const tempJ = (j - 1).mod(substr.length); - logger.println('they\'re NOT equal'); - trackTracer.select(tempJ); - Tracer.delay(); - stringTracer.deselect(j); - Tracer.delay(); - - j = track[tempJ]; // use modulo to wrap around, i.e., if index = -1, access the LAST element of array (PYTHON-LIKE) - - logger.println(`Setting j to ${j}`); - stringTracer.select(j); - Tracer.delay(); - trackTracer.deselect(tempJ); - Tracer.delay(); +function KMP(string, pattern) +{ + const match_positions = []; + let match_start_position; + + let i = 0; // string pointer + let k = 0; // pattern pointer + get_next(pattern); + for (; i < string.length; i++) + { + // visualize { + string_tracer.select(i); + pattern_tracer.select(1, k); Tracer.delay(); + // } + while ((k > 0) && (string[i] != pattern[k])) + { + // visualize { + pattern_tracer.select(0, k - 1); Tracer.delay(); + pattern_tracer.deselect(1, k); + pattern_tracer.select(1, _next[k - 1]); Tracer.delay(); + pattern_tracer.deselect(0, k - 1); + // } + k = _next[k - 1]; + } + if (string[i] === pattern[k]) + { + ++k; + if (k === pattern.length) + { + match_start_position = i - pattern.length + 1; + match_positions.push(match_start_position); + // visualize { + string_tracer.select(match_start_position, match_start_position + pattern.length - 1); Tracer.delay(); + string_tracer.deselect(match_start_position, match_start_position + pattern.length - 1); Tracer.delay(); + pattern_tracer.select(0, k - 1); Tracer.delay(); + pattern_tracer.deselect(1, k - 1); + pattern_tracer.select(1, _next[k - 1]); Tracer.delay(); + pattern_tracer.deselect(0, k - 1); + // } + k = _next[k - 1]; + } + else + { + // visualize { + pattern_tracer.deselect(1, k - 1); + pattern_tracer.select(1, k); Tracer.delay(); + // } + } + } + else + { + // visualize { + pattern_tracer.select(0, k); Tracer.delay(); + // } + } + // visualize { + pattern_tracer.deselect(0, k); + pattern_tracer.deselect(1, k); + string_tracer.deselect(i); + // } } - - stringTracer.deselect(i); - Tracer.delay(); - } - - return positions; + // visualize { + for (let j = 0; j < match_positions.length; j++) + { + string_tracer.select(match_positions[j], match_positions[j] + pattern.length - 1); Tracer.delay(); + string_tracer.deselect(match_positions[j], match_positions[j] + pattern.length - 1); + } + // } } -const positions = kmp(string, substring); - -logger.println(`Substring positions are: ${positions.length ? String(positions) : 'NONE'}`); -for (let i = 0; i < positions.length; i++) { - stringTracer.select(positions[i], positions[i] + substring.length - 1); - Tracer.delay(); -} +KMP(string, pattern); From 27ba04565f38990803b1213e76ef4451e0a13f77 Mon Sep 17 00:00:00 2001 From: Qihao Ye <11610812@mail.sustc.edu.cn> Date: Wed, 16 Oct 2019 15:30:00 +0800 Subject: [PATCH 15/26] Try to solve code folding problem (#15) * Improve Knuth-Morris-Pratt's String Search The original code.js has both display and correctness errors. * Reconstruct Knuth-Morris-Pratt's String Search/code.js 1. Add code foldings 2. Delete log tracer to simplify the content 3. Delete redundant display steps 4. Indent using 4 spaces 5. Rename variables 6. Use fixed pattern and string to illustrate * Try to add code folding * Try to add code folding * Try to fix remain errors * Fix typo --- Brute Force/Insertion Sort/code.js | 14 ++++++ Brute Force/Lowest Common Ancestor/code.js | 14 ++++++ Brute Force/PageRank/code.js | 38 ++++++++++++++- Brute Force/Pancake Sort/code.js | 23 +++++++++ .../Rabin-Karp's String Search/code.js | 12 +++++ Brute Force/Selection Sort/code.js | 22 +++++++++ Brute Force/Shellsort/code.js | 20 ++++++++ .../code.js | 45 +++++++++++++---- Divide and Conquer/Merge Sort/bottomUp.js | 24 ++++++---- Divide and Conquer/Merge Sort/topDown.js | 28 +++++++++++ Divide and Conquer/Pigeonhole Sort/code.js | 20 ++++++++ Divide and Conquer/Quicksort/code.js | 20 ++++++++ .../Radix Sort/leastSignificantDigit.js | 30 ++++++++++++ .../Bellman-Ford's Shortest Path/code.js | 26 ++++++++++ Dynamic Programming/Catalan Number/code.js | 12 +++++ .../Fibonacci Sequence/code.js | 6 +++ .../Floyd-Warshall's Shortest Path/code.js | 20 ++++++++ Dynamic Programming/Integer Partition/code.js | 14 ++++++ Dynamic Programming/Knapsack Problem/code.js | 18 +++++++ .../Levenshtein's Edit Distance/code.js | 26 ++++++++-- .../Longest Common Subsequence/code.js | 20 ++++++++ .../Longest Increasing Subsequence/code.js | 18 +++++++ .../Longest Palindromic Subsequence/code.js | 45 +++++++++++++++-- Dynamic Programming/Maximum Subarray/code.js | 23 ++++++++- Dynamic Programming/Maximum Sum Path/code.js | 20 ++++++++ Dynamic Programming/Pascal's Triangle/code.js | 10 ++++ .../Shortest Common Supersequence/code.js | 16 +++++++ .../Sieve of Eratosthenes/code.js | 17 ++++++- Dynamic Programming/Sliding Window/code.js | 10 ++++ Dynamic Programming/Ugly Numbers/code.js | 14 ++++++ Dynamic Programming/Z String Search/code.js | 42 +++++++++++++--- .../code.js" | 40 ++++++++++++++++ Greedy/Dijkstra's Shortest Path/code.js | 25 ++++++++-- Greedy/Job Scheduling Problem/code.js | 25 +++++++--- .../Kruskal's Minimum Spanning Tree/code.js | 10 ++++ Greedy/Prim's Minimum Spanning Tree/code.js | 14 ++++++ Greedy/Stable Matching/code.js | 18 +++++++ Simple Recursive/Cellular Automata/code.js | 11 +++++ .../Euclidean Greatest Common Divisor/code.js | 23 ++++++++- Simple Recursive/Suffix Array/code.js | 22 +++++++++ Uncategorized/Affine Cipher/code.js | 23 +++++++++ Uncategorized/Caesar Cipher/code.js | 26 ++++++++++ .../code.js | 14 ++++++ Uncategorized/Magic Square/code.js | 18 +++++++ Uncategorized/Maze Generation/code.js | 48 +++++++++++++++++-- .../Miller-Rabin's Primality Test/code.js | 32 +++++++++++++ 46 files changed, 966 insertions(+), 50 deletions(-) diff --git a/Brute Force/Insertion Sort/code.js b/Brute Force/Insertion Sort/code.js index 462a66cd..7b3db3d0 100644 --- a/Brute Force/Insertion Sort/code.js +++ b/Brute Force/Insertion Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,24 +11,35 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } for (let i = 1; i < D.length; i++) { const key = D[i]; + // visualize { logger.println(`insert ${key}`); tracer.select(i); Tracer.delay(); + // } let j; for (j = i - 1; (j >= 0) && (D[j] > key); j--) { D[j + 1] = D[j]; + // visualize { tracer.patch(j + 1, D[j + 1]); Tracer.delay(); tracer.depatch(j + 1); + // } } D[j + 1] = key; + // visualize { tracer.patch(j + 1, D[j + 1]); Tracer.delay(); tracer.depatch(j + 1); tracer.deselect(i); + // } } +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Lowest Common Ancestor/code.js b/Brute Force/Lowest Common Ancestor/code.js index 309a4881..b3b8df64 100644 --- a/Brute Force/Lowest Common Ancestor/code.js +++ b/Brute Force/Lowest Common Ancestor/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,23 +30,31 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer(' Traversal Pre-order '); const logger = new LogTracer(' Log '); Layout.setRoot(new VerticalLayout([treeTracer, logger])); treeTracer.set(G); treeTracer.layoutTree(5); Tracer.delay(); +// } function lcaBT(parent, root, a, b) { + // logger { logger.println(`Beginning new Iteration of lcaBT () with parent: ${parent}, current root: ${root}`); + // } if (root === -1) { + // logger { logger.println('Reached end of path & target node(s) not found'); + // } return null; } + // visualize { if (parent !== null) treeTracer.visit(root, parent); else treeTracer.visit(root); Tracer.delay(); + // visualize { if (root === a || root === b) return root; @@ -53,8 +63,10 @@ function lcaBT(parent, root, a, b) { if (left !== null && right !== null) return root; if (left === null && right === null) { + // visualize { treeTracer.leave(root, parent); Tracer.delay(); + // } } return (left !== null ? left : right); @@ -62,4 +74,6 @@ function lcaBT(parent, root, a, b) { const a = 7; const b = 2; +// logger { logger.println(`Lowest common ancestor of ${a} & ${b} is: ${lcaBT(null, 5, a, b)}`); +// } diff --git a/Brute Force/PageRank/code.js b/Brute Force/PageRank/code.js index 69e9c82d..8332c37c 100644 --- a/Brute Force/PageRank/code.js +++ b/Brute Force/PageRank/code.js @@ -1,9 +1,12 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } function filledArray(length, value) { return Array(...Array(length)).map(Number.prototype.valueOf, value); } +// define tracer variables { const G = Randomize.Graph({ N: 5, ratio: .4 }); let ranks; const outgoingEdgeCounts = filledArray(G.length, 0); @@ -22,6 +25,7 @@ oecTracer.set(outgoingEdgeCounts); for (incomingNodes = []; incomingNodes.length < G.length; incomingNodes.push(filledArray(G.length, -1))) ; inTracer.set(incomingNodes); Tracer.delay(); +// } /* PageRank Algorithm Version 2 @@ -41,40 +45,51 @@ function arraySum(array) { function showOutgoingEdges(i) { G[i].forEach((edgeExists, j) => { if (edgeExists) { + // visualize { graphTracer.visit(j, i); Tracer.delay(); graphTracer.leave(j, i); Tracer.delay(); + // } } }); } // PRECOMPUTATIONS +// logger { logger.println('Calculate Outgoing Edge Count for each Node'); +// } (function calculateOEC() { G.forEach((relations, i) => { outgoingEdgeCounts[i] = arraySum(relations); showOutgoingEdges(i); + // visualize { oecTracer.patch(i, outgoingEdgeCounts[i]); Tracer.delay(); oecTracer.depatch(i); Tracer.delay(); + // } }); }()); +// logger { logger.println('determine incoming nodes for each node'); +// } (function determineIN() { for (let i = 0; i < G.length; i++) { for (let j = 0; j < G.length; j++) { if (G[i][j]) { // there's an edge FROM i TO j + // visualize { graphTracer.visit(j, i); Tracer.delay(); + // } const nextPos = incomingNodes[j].indexOf(-1); incomingNodes[j][nextPos] = i; + // visualize { inTracer.patch(j, nextPos, i); Tracer.delay(); inTracer.depatch(j, nextPos); @@ -82,6 +97,7 @@ logger.println('determine incoming nodes for each node'); graphTracer.leave(j, i); Tracer.delay(); + // } } } } @@ -96,27 +112,37 @@ function updateRank(nodeIndex) { let inNodeSummation = 0; let result; + // logger { logger.println(`Updating rank of ${nodeIndex}`); logger.println(`The incoming Nodes of ${nodeIndex} are being highlighted`); + // } incomingNodes[nodeIndex].forEach((incoming, i) => { + // visualize { inTracer.select(nodeIndex, i); Tracer.delay(); logger.println(`Outgoing edge count of ${incoming} is ${outgoingEdgeCounts[incoming]}`); oecTracer.select(incoming); Tracer.delay(); + // } inNodeSummation += (ranks[incoming] / outgoingEdgeCounts[incoming]); + // visualize { oecTracer.deselect(incoming); Tracer.delay(); inTracer.deselect(nodeIndex, i); Tracer.delay(); + // } }); + // logger { logger.println(`In-Node summation of ${nodeIndex} = ${inNodeSummation}`); - + // } + result = ((1 - damping) / G.length) + (damping * inNodeSummation); // notice the subtle difference between equations of Basic PR & PR version 2 (divide by N) + // logger { logger.println(`Therefore, using Equation, new rank of ${nodeIndex} = ${result}`); + // } return result; } @@ -124,27 +150,37 @@ let damping = 0.85; let iterations = 7; const initialRank = 1.0; +// logger { logger.println(`Initialized all Page ranks to ${initialRank}`); +// } ranks = filledArray(G.length, initialRank); +// visualize { rankTracer.set(ranks); +// } +// logger { logger.println('Begin execution of PageRank Version #1'); logger.println('Equation used: PR (X) = (1 - D) + D (In-Node-Summation i->X (PR (I) / Out (i)))'); logger.println('D = Damping Factor, PR (X) = Page rank of Node X, i = the ith In-Node of X, Out (i) = outgoing Edge Count of i'); logger.println(''); +// } while (iterations--) { for (let node = 0; node < ranks.length; node++) { ranks[node] = updateRank(node); + // visualize { rankTracer.patch(node, ranks[node]); Tracer.delay(); rankTracer.patch(node); Tracer.delay(); + // } } } +// logger { logger.println('Page Ranks have been converged to.'); ranks.forEach((rank, node) => { logger.println(`Rank of Node #${node} = ${rank}`); }); logger.println('Done'); +// } diff --git a/Brute Force/Pancake Sort/code.js b/Brute Force/Pancake Sort/code.js index f520a64a..4e066872 100644 --- a/Brute Force/Pancake Sort/code.js +++ b/Brute Force/Pancake Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,43 +11,63 @@ const D = Randomize.Array1D({ N: 10 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } const N = D.length; function flip(start) { + // visualize { tracer.select(start, N - 1); Tracer.delay(); + // } let idx = 0; for (let i = start; i < (start + N) / 2; i++) { + // visualize { tracer.select(i); Tracer.delay(); + // } const temp = D[i]; D[i] = D[N - idx - 1]; D[N - idx - 1] = temp; + // visualize { tracer.patch(i, D[i]); tracer.patch(N - idx - 1, D[N - idx - 1]); Tracer.delay(); tracer.depatch(i); tracer.depatch(N - idx - 1); tracer.deselect(i); + // } idx++; } + // visualize { tracer.deselect(start, N - 1); + // } } for (let i = 0; i < N - 1; i++) { + // logger { logger.println(`round ${i + 1}`); + // } const currArr = D.slice(i, N); const currMax = currArr.reduce((prev, curr, idx) => ((curr > prev.val) ? { idx, val: curr } : prev), { idx: 0, val: currArr[0], }); if (currMax.idx !== 0) { // if currMax.idx === 0 that means max element already at the bottom, no flip required + // logger { logger.println(`flip at ${currMax.idx + i} (step 1)`); + // } flip(currMax.idx + i, N); + // logger { logger.println(`flip at ${i} (step 2)`); + // } flip(i, N); } } + +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Rabin-Karp's String Search/code.js b/Brute Force/Rabin-Karp's String Search/code.js index 7ede6390..ef9d1e58 100644 --- a/Brute Force/Rabin-Karp's String Search/code.js +++ b/Brute Force/Rabin-Karp's String Search/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const text = ['h', 'e', 'l', 'l', 'o', ' ', 's', 'i', 'r', ' ', 'h', 'e', 'l', 'l', 'o']; const pattern = ['h', 'e', 'l', 'l', 'o']; @@ -6,6 +8,7 @@ const pattern = ['h', 'e', 'l', 'l', 'o']; const Q = 101; // A prime number const D = 256; // number of characters in the input alphabet +// define tracer variables { const logger = new LogTracer(); const tracer1 = new Array1DTracer('Text'); const tracer2 = new Array1DTracer('Pattern'); @@ -13,6 +16,7 @@ Layout.setRoot(new VerticalLayout([logger, tracer1, tracer2])); tracer1.set(text); tracer2.set(pattern); Tracer.delay(); +// } const N = text.length; const M = pattern.length; @@ -38,27 +42,35 @@ for (let i = 0; i <= N - M; i++) { */ if (hashPattern === hashText) { let f = 0; + // visualize { tracer1.select(i, i + M - 1); Tracer.delay(); tracer2.select(0, M - 1); Tracer.delay(); + // } for (let j = 0; j < M; j++) { + // visualize { tracer1.patch(i + j); Tracer.delay(); tracer2.patch(j); Tracer.delay(); + // } if (text[i + j] !== pattern[j]) { f++; } + // visualize { tracer1.depatch(i + j); tracer2.depatch(j); + // } } + // visualize { if (f === 0) { logger.println(` Pattern found at index ${i}`); } tracer1.deselect(i, i + M); tracer2.deselect(0, M - 1); + // } } /* diff --git a/Brute Force/Selection Sort/code.js b/Brute Force/Selection Sort/code.js index d7316338..41af8a11 100644 --- a/Brute Force/Selection Sort/code.js +++ b/Brute Force/Selection Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,34 +11,53 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } for (let i = 0; i < D.length - 1; i++) { let minJ = i; + // visualize { tracer.select(i); Tracer.delay(); + // } for (let j = i + 1; j < D.length; j++) { + // visualize { tracer.select(j); Tracer.delay(); + // } if (D[j] < D[minJ]) { minJ = j; + // visualize { tracer.patch(j); Tracer.delay(); tracer.depatch(j); + // } } + // visualize { tracer.deselect(j); + // } } if (minJ !== i) { + // logger { logger.println(`swap ${D[i]} and ${D[minJ]}`); + // } const temp = D[i]; D[i] = D[minJ]; D[minJ] = temp; + // visualize { tracer.patch(i, D[i]); tracer.patch(minJ, D[minJ]); Tracer.delay(); tracer.depatch(i); tracer.depatch(minJ); + // } } + // visualize { tracer.deselect(i); + // } } +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Shellsort/code.js b/Brute Force/Shellsort/code.js index d13739be..333ad2ce 100644 --- a/Brute Force/Shellsort/code.js +++ b/Brute Force/Shellsort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,29 +11,43 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`Original array = [${D.join(', ')}]`); +// } const N = D.length; for (let gap = N; gap = parseInt(gap / 2);) { + // logger { logger.println(''); logger.println(`Gap of ${gap}`); + // } for (let i = gap; i < N; i++) { + // visualize { tracer.select(i); tracer.select(i - gap); Tracer.delay(); + // } const k = D[i]; + // logger { logger.println(`Holding: ${k}`); + // } let j; for (j = i; j >= gap && k < D[j - gap]; j -= gap) { + // logger { logger.println(`${k} < ${D[j - gap]}`); + // } D[j] = D[j - gap]; + // visualize { tracer.patch(j, D[j]); Tracer.delay(); tracer.depatch(j); + // } } const old = D[j]; D[j] = k; + // visualize { if (old !== k) { tracer.patch(j, D[j]); Tracer.delay(); @@ -40,7 +57,10 @@ for (let gap = N; gap = parseInt(gap / 2);) { tracer.deselect(i); tracer.deselect(i - gap); + // } } } +// logger { logger.println(''); logger.println(`Sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Tarjan's Strongly Connected Components/code.js b/Brute Force/Tarjan's Strongly Connected Components/code.js index 0bcc0c63..415c5838 100644 --- a/Brute Force/Tarjan's Strongly Connected Components/code.js +++ b/Brute Force/Tarjan's Strongly Connected Components/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ [0, 0, 1, 1, 0, 0], @@ -9,16 +11,6 @@ const G = [ [0, 0, 0, 0, 1, 0], ]; -const graphTracer = new GraphTracer(); -graphTracer.set(G); - -const discTracer = new Array1DTracer('Disc'); -const lowTracer = new Array1DTracer('Low'); -const stackMemberTracer = new Array1DTracer('stackMember'); -const stTracer = new Array1DTracer('st'); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([graphTracer, discTracer, lowTracer, stackMemberTracer, stTracer, logger])); - const disc = new Array(G.length); const low = new Array(G.length); const stackMember = new Array(G.length); @@ -31,31 +23,51 @@ for (let i = 0; i < G.length; i++) { stackMember[i] = false; } +// define tracer variables { +const graphTracer = new GraphTracer(); +graphTracer.set(G); +const discTracer = new Array1DTracer('Disc'); +const lowTracer = new Array1DTracer('Low'); +const stackMemberTracer = new Array1DTracer('stackMember'); +const stTracer = new Array1DTracer('st'); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([graphTracer, discTracer, lowTracer, stackMemberTracer, stTracer, logger])); discTracer.set(disc); lowTracer.set(low); stackMemberTracer.set(stackMember); stTracer.set(st); Tracer.delay(); +// } function SCCVertex(u, disc, low, st, stackMember, carry) { + // visualize { graphTracer.visit(u); Tracer.delay(); + // } disc[u] = ++carry.time; + // visualize { discTracer.patch(u, carry.time); Tracer.delay(); + // } low[u] = carry.time; + // visualize { lowTracer.patch(u, carry.time); Tracer.delay(); + // } st.push(u); + // visualize { stTracer.set(st); Tracer.delay(); + // } stackMember[u] = true; + // visualize { stackMemberTracer.patch(u, true); Tracer.delay(); + // } // Go through all vertices adjacent to this for (let v = 0; v < G[u].length; v++) { @@ -67,15 +79,20 @@ function SCCVertex(u, disc, low, st, stackMember, carry) { // Check if the subtree rooted with 'v' has a // connection to one of the ancestors of 'u' low[u] = Math.min(low[u], low[v]); + // visualize { lowTracer.patch(u, low[u]); + Tracer.delay(); + // } } // Update low value of 'u' only of 'v' is still in stack // (i.e. it's a back edge, not cross edge). else if (stackMember[v] === true) { low[u] = Math.min(low[u], disc[v]); + // visualize { lowTracer.patch(u, low[u]); Tracer.delay(); + // } } } } @@ -85,28 +102,36 @@ function SCCVertex(u, disc, low, st, stackMember, carry) { if (low[u] === disc[u]) { while (st[st.length - 1] !== u) { w = st.pop(); + // visualize { stTracer.set(st); Tracer.delay(); logger.println(w); Tracer.delay(); + // } stackMember[w] = false; + // visualize { stackMemberTracer.patch(w, false); Tracer.delay(); + // } } w = st.pop(); + // visualize { stTracer.set(st); Tracer.delay(); logger.println(w); Tracer.delay(); logger.println('------'); + // } stackMember[w] = false; + // visualize { stackMemberTracer.patch(w, false); Tracer.delay(); + // } } } diff --git a/Divide and Conquer/Merge Sort/bottomUp.js b/Divide and Conquer/Merge Sort/bottomUp.js index 195e8f47..e3200fed 100644 --- a/Divide and Conquer/Merge Sort/bottomUp.js +++ b/Divide and Conquer/Merge Sort/bottomUp.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -10,8 +13,11 @@ const D = [ tracer.set(D); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D[0].join(', ')}]`); +// } function mergeSort(start, end) { if (Math.abs(end - start) <= 1) return; @@ -21,7 +27,7 @@ function mergeSort(start, end) { let width; let i; for (width = 1; width < end; width *= 2) { - // visualization { + // visualize { logger.println(`merging arrays of width: ${width}`); // } for (i = 0; i < end; i += 2 * width) { @@ -34,7 +40,7 @@ function mergeSort(start, end) { mergeTo = 1 - mergeFrom; } if (mergeFrom !== 0) { - // visualization { + // visualize { logger.println('final copy to original'); // } copy(mergeFrom, mergeTo, start, end); @@ -47,7 +53,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { let k; // in an actual merge implementation, mergeFrom and mergeTo would be arrays // here for the ability to trace what is going on better, the arrays are D[mergeFrom] and D[mergeTo] - // visualization { + // visualize { logger.println(`merging segments [${start}..${middle}] and [${middle}..${end}]`); tracer.selectRow(mergeFrom, start, end - 1); Tracer.delay(); @@ -55,7 +61,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { // } for (k = start; k < end; k++) { - // visualization { + // visualize { if (j < end) { tracer.select(mergeFrom, j); } @@ -69,7 +75,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { // } if (i < middle && (j >= end || D[mergeFrom][i] <= D[mergeFrom][j])) { - // visualization { + // visualize { if (j < end) { logger.println('writing smaller value to output'); } else { @@ -84,7 +90,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { D[mergeTo][k] = D[mergeFrom][i]; i += 1; } else { - // visualization { + // visualize { if (i < middle) { logger.println('writing smaller value to output'); } else { @@ -105,7 +111,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { function copy(mergeFrom, mergeTo, start, end) { let i; for (i = start; i < end; i++) { - // visualization { + // visualize { tracer.select(mergeFrom, i); tracer.patch(mergeTo, i, D[mergeFrom][i]); Tracer.delay(); @@ -113,7 +119,7 @@ function copy(mergeFrom, mergeTo, start, end) { D[mergeTo][i] = D[mergeFrom][i]; - // visualization { + // visualize { tracer.deselect(mergeFrom, i); tracer.depatch(mergeTo, i); // } @@ -121,4 +127,6 @@ function copy(mergeFrom, mergeTo, start, end) { } mergeSort(0, D[0].length); +// logger { logger.println(`sorted array = [${D[0].join(', ')}]`); +// } diff --git a/Divide and Conquer/Merge Sort/topDown.js b/Divide and Conquer/Merge Sort/topDown.js index eac4f824..9ad9b208 100644 --- a/Divide and Conquer/Merge Sort/topDown.js +++ b/Divide and Conquer/Merge Sort/topDown.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } function mergeSort(start, end) { if (Math.abs(end - start) <= 1) return []; @@ -18,7 +24,9 @@ function mergeSort(start, end) { mergeSort(start, middle); mergeSort(middle, end); + // logger { logger.println(`divide left[${start}, ${middle - 1}], right[${middle}, ${end - 1}]`); + // } return mergeSort.merge(start, middle, end); } @@ -34,48 +42,68 @@ mergeSort.merge = (start, middle, end) => { for (i = 0; i < maxSize; i++) { if (i < leftSize) { left.push(D[start + i]); + // visualize { tracer.select(start + i); logger.println(`insert value into left array[${i}] = ${D[start + i]}`); Tracer.delay(); + // } } if (i < rightSize) { right.push(D[middle + i]); + // visualize { tracer.select(middle + i); logger.println(`insert value into right array[${i}] = ${D[middle + i]}`); Tracer.delay(); + // } } } + // logger { logger.println(`left array = [${left.join(', ')}], ` + `right array = [${right.join(', ')}]`); + // } i = 0; while (i < size) { if (left[0] && right[0]) { if (left[0] > right[0]) { D[start + i] = right.shift(); + // logger { logger.println(`rewrite from right array[${i}] = ${D[start + i]}`); + // } } else { D[start + i] = left.shift(); + // logger { logger.println(`rewrite from left array[${i}] = ${D[start + i]}`); + // } } } else if (left[0]) { D[start + i] = left.shift(); + // logger { logger.println(`rewrite from left array[${i}] = ${D[start + i]}`); + // } } else { D[start + i] = right.shift(); + // logger { logger.println(`rewrite from right array[${i}] = ${D[start + i]}`); + // } } + // visualize { tracer.deselect(start + i); tracer.patch(start + i, D[start + i]); Tracer.delay(); tracer.depatch(start + i); + // } i++; } const tempArray = []; for (i = start; i < end; i++) tempArray.push(D[i]); + // logger { logger.println(`merged array = [${tempArray.join(', ')}]`); + // } }; mergeSort(0, D.length); +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Divide and Conquer/Pigeonhole Sort/code.js b/Divide and Conquer/Pigeonhole Sort/code.js index 27923636..4617cdaf 100644 --- a/Divide and Conquer/Pigeonhole Sort/code.js +++ b/Divide and Conquer/Pigeonhole Sort/code.js @@ -1,14 +1,18 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const A = Randomize.Array1D({ N: 7 }); const N = A.length; +// define tracer variables { const tracer1 = new Array1DTracer('Array'); const tracer2 = new Array2DTracer('Holes'); const logTracer = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracer1, tracer2, logTracer])); tracer1.set(A); Tracer.delay(); +// } let min = A[0]; let max = A[0]; @@ -27,31 +31,47 @@ const holes = new Array(range); for (let i = 0; i < range; i++) { holes[i] = []; } +// visualize { tracer2.set(holes); +// } +// logger { logTracer.println('Filling up holes'); +// } for (let i = 0; i < N; i++) { + // visualize { tracer1.select(i); Tracer.delay(); + // } holes[A[i] - min].push(A[i]); + // visualize { tracer2.set(holes); tracer1.deselect(i); + // } } +// logger { logTracer.println('Building sorted array'); +// } let k = 0; for (let i = 0; i < range; i++) { for (let j = 0; j < holes[i].length; j++) { + // visualize { tracer2.select(i, j); Tracer.delay(); + // } A[k++] = holes[i][j]; + // visualize { tracer1.patch(k - 1, A[k - 1]); Tracer.delay(); tracer2.deselect(i, j); tracer1.depatch(k - 1); + // } } } +// logger { logTracer.println(`Sorted array is ${A}`); +// } diff --git a/Divide and Conquer/Quicksort/code.js b/Divide and Conquer/Quicksort/code.js index 0cd46345..4eb5373b 100644 --- a/Divide and Conquer/Quicksort/code.js +++ b/Divide and Conquer/Quicksort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } function partition(D, low, high) { let i; @@ -20,36 +26,48 @@ function partition(D, low, high) { j = high; s = D[low]; while (i < j) { + // visualize { tracer.select(high); tracer.select(low); Tracer.delay(); + // } while (D[j] > s) { + // visualize { tracer.select(j); Tracer.delay(); tracer.deselect(j); + // } j--; } D[i] = D[j]; + // visualize { tracer.patch(i, D[j]); Tracer.delay(); tracer.depatch(i); + // } while (s >= D[i] && i < j) { + // visualize { tracer.select(i); Tracer.delay(); tracer.deselect(i); + // } i++; } D[j] = D[i]; + // visualize { tracer.patch(j, D[i]); Tracer.delay(); tracer.depatch(j); tracer.deselect(high); tracer.deselect(low); + // } } D[i] = s; + // visualize { tracer.patch(i, s); Tracer.delay(); tracer.depatch(i); + // } partition(D, low, i - 1); low = i + 1; } @@ -60,4 +78,6 @@ function quicksort(D) { } quicksort(D); +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Divide and Conquer/Radix Sort/leastSignificantDigit.js b/Divide and Conquer/Radix Sort/leastSignificantDigit.js index 7a7c21d1..1d0d3ea6 100644 --- a/Divide and Conquer/Radix Sort/leastSignificantDigit.js +++ b/Divide and Conquer/Radix Sort/leastSignificantDigit.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -11,8 +14,11 @@ const D = [ ]; tracer.set(D); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D[0].join(', ')}]`); +// } function pow(base, expo) { let ans = 1; @@ -27,55 +33,79 @@ function digit(i, exp) { } for (let exp = 0; exp < 3; exp++) { + // logger { logger.println(`Digit: ${exp}`); + // } let i; for (i = 0; i < D[0].length; i++) { const d = digit(i, exp); + // visualize { tracer.select(0, i); Tracer.delay(); + // } D[2][d] += 1; + // visualize { tracer.patch(2, d, D[2][d]); Tracer.delay(); tracer.depatch(2, d); tracer.deselect(0, i); + // } } for (i = 1; i < 10; i++) { + // visualize { tracer.select(2, i - 1); Tracer.delay(); + // } D[2][i] += D[2][i - 1]; + // visualize { tracer.patch(2, i, D[2][i]); Tracer.delay(); tracer.depatch(2, i); tracer.deselect(2, i - 1); + // } } for (i = D[0].length - 1; i >= 0; i--) { const d = digit(i, exp); + // visualize { tracer.select(0, i); Tracer.delay(); + // } D[2][d] -= 1; + // visualize { tracer.patch(2, d, D[2][d]); Tracer.delay(); tracer.depatch(2, d); + // } D[1][D[2][d]] = D[0][i]; + // visualize { tracer.patch(1, D[2][d], D[1][D[2][d]]); Tracer.delay(); tracer.depatch(1, D[2][d]); tracer.deselect(0, i); + // } } for (i = 0; i < D[0].length; i++) { + // visualize { tracer.select(1, i); Tracer.delay(); + // } D[0][i] = D[1][i]; + // visualize { tracer.patch(0, i, D[0][i]); Tracer.delay(); tracer.depatch(0, i); tracer.deselect(1, i); + // } } for (i = 0; i < 10; i++) { D[2][i] = 0; + // visualize { tracer.patch(2, i, D[2][i]); Tracer.delay(); tracer.depatch(2, i); + // } } } +// logger { logger.println(`sorted array = [${D[0].join(', ')}]`); +// } diff --git a/Dynamic Programming/Bellman-Ford's Shortest Path/code.js b/Dynamic Programming/Bellman-Ford's Shortest Path/code.js index 2bd0925c..69cae5bb 100644 --- a/Dynamic Programming/Bellman-Ford's Shortest Path/code.js +++ b/Dynamic Programming/Bellman-Ford's Shortest Path/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,6 +10,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: .5, value: () => Randomize.Integer({ min: -2, max: 5 }), weighted: true }); tracer.set(G); Tracer.delay(); +// } function BELLMAN_FORD(src, dest) { const weights = new Array(G.length); @@ -15,37 +19,51 @@ function BELLMAN_FORD(src, dest) { for (i = 0; i < G.length; i++) { weights[i] = MAX_VALUE; + // visualize { tracer.updateNode(i, weights[i]); + // } } weights[src] = 0; + // visualize { tracer.updateNode(src, 0); + // } + // logger { logger.println(`Initializing weights to: [${weights}]`); logger.println(''); + // } // begin BF algorithm execution let k = G.length; while (k--) { + // logger { logger.println(`Iteration: ${G.length - k}`); logger.println('------------------------------------------------------------------'); + // } for (i = 0; i < G.length; i++) { for (j = 0; j < G.length; j++) { if (G[i][j]) { // proceed to relax Edges only if a particular weight !== 0 (0 represents no edge) if (weights[j] > (weights[i] + G[i][j])) { weights[j] = weights[i] + G[i][j]; + // logger { logger.println(`weights[${j}] = weights[${i}] + ${G[i][j]}`); + // } } + // visualize { tracer.visit(j, i, weights[j]); Tracer.delay(); tracer.leave(j, i); Tracer.delay(); + // } } } } + // logger { logger.println(`updated weights: [${weights.join(', ')}]`); logger.println(''); + // } } // check for cycle @@ -54,14 +72,18 @@ function BELLMAN_FORD(src, dest) { for (j = 0; j < G.length; j++) { if (G[i][j]) { if (weights[j] > (weights[i] + G[i][j])) { + // logger { logger.println(`A cycle was detected: weights[${j}] > weights[${i}] + ${G[i][j]}`); + // } return (MAX_VALUE); } } } } + // logger { logger.println(`No cycles detected. Final weights for the source ${src} are: [${weights}]`); + // } return weights[dest]; } @@ -81,12 +103,16 @@ do { } while (src === dest); +// logger { logger.println(`finding the shortest path from ${src} to ${dest}`); +// } minWeight = BELLMAN_FORD(src, dest); +// logger { if (minWeight === MAX_VALUE) { logger.println(`there is no path from ${src} to ${dest}`); } else { logger.println(`the shortest path from ${src} to ${dest} is ${minWeight}`); } +// } diff --git a/Dynamic Programming/Catalan Number/code.js b/Dynamic Programming/Catalan Number/code.js index 74c520cd..f9b4830c 100644 --- a/Dynamic Programming/Catalan Number/code.js +++ b/Dynamic Programming/Catalan Number/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 10; const A = new Array(N + 1); @@ -6,24 +8,31 @@ for (let i = N; i >= 0; i--) { A[i] = 0; } +// define tracer variables { const tracer = new Array1DTracer(' Catalan Numbers '); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(A); Tracer.delay(); +// } A[0] = 1; +// visualize { tracer.patch(0, A[0]); Tracer.delay(); tracer.depatch(0); +// } A[1] = 1; +// visualize { tracer.patch(1, A[1]); Tracer.delay(); tracer.depatch(1); +// } for (let i = 2; i <= N; i++) { for (let j = 0; j < i; j++) { A[i] += A[j] * A[i - j - 1]; + // visualize { tracer.select(j); Tracer.delay(); tracer.select(i - j - 1); @@ -33,9 +42,12 @@ for (let i = 2; i <= N; i++) { tracer.deselect(j); tracer.deselect(i - j - 1); tracer.depatch(i); + // } } } +// visualize { logger.println(` The ${N}th Catalan Number is ${A[N]}`); tracer.select(N); Tracer.delay(); +// } diff --git a/Dynamic Programming/Fibonacci Sequence/code.js b/Dynamic Programming/Fibonacci Sequence/code.js index 66910bf6..3f10a27b 100644 --- a/Dynamic Programming/Fibonacci Sequence/code.js +++ b/Dynamic Programming/Fibonacci Sequence/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array1DTracer('Sequence'); Layout.setRoot(new VerticalLayout([tracer])); const index = 15; @@ -9,13 +12,16 @@ for (let i = 2; i < index; i++) { } tracer.set(D); Tracer.delay(); +// } for (let i = 2; i < index; i++) { D[i] = D[i - 2] + D[i - 1]; + // visualize { tracer.select(i - 2, i - 1); Tracer.delay(); tracer.patch(i, D[i]); Tracer.delay(); tracer.depatch(i); tracer.deselect(i - 2, i - 1); + // } } diff --git a/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js b/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js index 5c8dd7e7..e526c293 100644 --- a/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js +++ b/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,6 +10,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, weighted: true }); tracer.set(G); Tracer.delay(); +// } function FloydWarshall() { // Finds the shortest path between all nodes @@ -27,32 +31,48 @@ function FloydWarshall() { for (let k = 0; k < G.length; k++) { for (let i = 0; i < G.length; i++) { if (k === i) continue; + // visualize { tracer.visit(k, i); Tracer.delay(); + // } for (let j = 0; j < G.length; j++) { if (i === j || j === k) continue; + // visualize { tracer.visit(j, k); Tracer.delay(); + // } if (S[i][j] > S[i][k] + S[k][j]) { + // visualize { tracer.visit(j, i, S[i][j]); Tracer.delay(); + // } S[i][j] = S[i][k] + S[k][j]; + // visualize { tracer.leave(j, i, S[i][j]); + // } } + // visualize { tracer.leave(j, k); + // } } + // visualize { tracer.leave(k, i); Tracer.delay(); + // } } } + // logger { for (let i = 0; i < G.length; i++) { for (let j = 0; j < G.length; j++) { if (S[i][j] === MAX_VALUE) logger.println(`there is no path from ${i} to ${j}`); else logger.println(`the shortest path from ${i} to ${j} is ${S[i][j]}`); } } + // } } let MAX_VALUE = Infinity; +// logger { logger.println('finding the shortest paths from and to all nodes'); +// } FloydWarshall(); diff --git a/Dynamic Programming/Integer Partition/code.js b/Dynamic Programming/Integer Partition/code.js index 0a4f969b..3618098c 100644 --- a/Dynamic Programming/Integer Partition/code.js +++ b/Dynamic Programming/Integer Partition/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -14,9 +17,12 @@ for (let i = 0; i <= integer; i++) { } tracer.set(D); Tracer.delay(); +// } function partition(A, n, p) { + // logger { if (n === 0) logger.println(`[${A.join(', ')}]`); + // } else { let end = n; if (p !== 0 && A[p - 1] < n) end = A[p - 1]; @@ -33,19 +39,27 @@ function integerPartition(n) { // We are allowed to use numbers from 2 to i for (let j = 1; j <= i; j++) { // Number of partitions without j number + number of partitions with max j + // visualize { tracer.select(i, j); Tracer.delay(); + // } D[i][j] = D[i][j - 1] + D[i - j][Math.max(j, i - j)]; + // visualize { tracer.patch(i, j, D[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.deselect(i, j); + // } } } return D[n][n]; } +// logger { logger.println(`Partitioning: ${integer}`); +// } partition(A, integer, 0); const part = integerPartition(integer); +// logger { logger.println(part); +// } diff --git a/Dynamic Programming/Knapsack Problem/code.js b/Dynamic Programming/Knapsack Problem/code.js index 83c5c567..8fc41c73 100644 --- a/Dynamic Programming/Knapsack Problem/code.js +++ b/Dynamic Programming/Knapsack Problem/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const val = [1, 4, 5, 7]; // The value of all available items const wt = [1, 3, 4, 5]; // The weights of available items @@ -13,6 +15,7 @@ for (let i = 0; i < N + 1; i++) { } } +// define tracer variables { const tracer = new Array2DTracer('Knapsack Table'); const dataViewer1 = new Array1DTracer('Values'); const dataViewer2 = new Array1DTracer('Weights'); @@ -22,6 +25,7 @@ tracer.set(DP); dataViewer1.set(val); dataViewer2.set(wt); Tracer.delay(); +// } for (let i = 0; i <= N; i++) { for (let j = 0; j <= W; j++) { @@ -31,16 +35,20 @@ for (let i = 0; i <= N; i++) { then the total weight in our collection is 0 */ DP[i][0] = 0; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); tracer.depatch(i, j); + // } } else if (wt[i - 1] <= j) { // take the current item in our collection + // visualize { dataViewer1.select(i - 1); Tracer.delay(); dataViewer2.select(i - 1); Tracer.delay(); tracer.select(i - 1, j); Tracer.delay(); + // } const A = val[i - 1] + DP[i - 1][j - wt[i - 1]]; const B = DP[i - 1][j]; @@ -50,25 +58,35 @@ for (let i = 0; i <= N; i++) { */ if (A > B) { DP[i][j] = A; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); + // } } else { DP[i][j] = B; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); + // } } + // visualize { tracer.deselect(i - 1, j); tracer.depatch(i, j); dataViewer2.deselect(i - 1); dataViewer1.deselect(i - 1); + // } } else { // leave the current item from our collection DP[i][j] = DP[i - 1][j]; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); tracer.depatch(i, j); + // } } } } +// logger { logger.println(` Best value we can achieve is ${DP[N][W]}`); +// } diff --git a/Dynamic Programming/Levenshtein's Edit Distance/code.js b/Dynamic Programming/Levenshtein's Edit Distance/code.js index f4e8d616..788678c2 100644 --- a/Dynamic Programming/Levenshtein's Edit Distance/code.js +++ b/Dynamic Programming/Levenshtein's Edit Distance/code.js @@ -1,8 +1,7 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array2DTracer('Distance Table'); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); const str1 = 'stack'; const str2 = 'racket'; const table = new Array(str1.length + 1); @@ -15,50 +14,71 @@ for (let i = 1; i < str2.length + 1; i++) { table[0][i] = i; } +// define tracer variables { +const tracer = new Array2DTracer('Distance Table'); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(table); Tracer.delay(); +// } +// logger { logger.println('Initialized DP Table'); logger.println(`Y-Axis (Top to Bottom): ${str1}`); logger.println(`X-Axis (Left to Right): ${str2}`); +// } const dist = (function editDistance(str1, str2, table) { // display grid with words + // logger { logger.println(`*** ${str2.split('').join(' ')}`); table.forEach((item, index) => { const character = (index === 0) ? '*' : str1[index - 1]; logger.println(`${character}\t${item}`); }); + // } // begin ED execution for (let i = 1; i < str1.length + 1; i++) { for (let j = 1; j < str2.length + 1; j++) { if (str1[i - 1] === str2[j - 1]) { + // visualize { tracer.select(i - 1, j - 1); Tracer.delay(); + // } table[i][j] = table[i - 1][j - 1]; + // visualize { tracer.patch(i, j, table[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.deselect(i - 1, j - 1); + // } } else { + // visualize { tracer.select(i - 1, j); tracer.select(i, j - 1); tracer.select(i - 1, j - 1); Tracer.delay(); + // } table[i][j] = Math.min(table[i - 1][j], table[i][j - 1], table[i - 1][j - 1]) + 1; + // visualize { tracer.patch(i, j, table[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.deselect(i - 1, j); tracer.deselect(i, j - 1); tracer.deselect(i - 1, j - 1); + // } } } } + // visualize { tracer.select(str1.length, str2.length); + // } return table[str1.length][str2.length]; }(str1, str2, table)); +// logger { logger.println(`Minimum Edit Distance: ${dist}`); +// } diff --git a/Dynamic Programming/Longest Common Subsequence/code.js b/Dynamic Programming/Longest Common Subsequence/code.js index 051a4ce3..eeb3e068 100644 --- a/Dynamic Programming/Longest Common Subsequence/code.js +++ b/Dynamic Programming/Longest Common Subsequence/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const string1 = 'AGGTAB'; const string2 = 'GXTXAYB'; @@ -9,6 +11,7 @@ for (let i = 0; i < m + 1; i++) { A[i] = new Array(n + 1); } +// define tracer variables { const tracer1 = new Array1DTracer('String 1'); const tracer2 = new Array1DTracer('String 2'); const tracer3 = new Array2DTracer('Memo Table'); @@ -18,6 +21,7 @@ tracer1.set(string1); tracer2.set(string2); tracer3.set(A); Tracer.delay(); +// } let i; let j; @@ -28,23 +32,29 @@ for (i = 0; i <= m; i++) { if (i === 0 || j === 0) { A[i][j] = 0; } else if (string1[i - 1] === string2[j - 1]) { + // visualize { tracer1.select(i - 1); Tracer.delay(); tracer2.select(j - 1); Tracer.delay(); tracer3.select(i - 1, j - 1); Tracer.delay(); + // } A[i][j] = A[i - 1][j - 1] + 1; + // visualize { tracer1.deselect(i - 1); tracer2.deselect(j - 1); tracer3.deselect(i - 1, j - 1); + // } } else { + // visualize { tracer3.select(i - 1, j); Tracer.delay(); tracer3.select(i, j - 1); Tracer.delay(); + // } if (A[i - 1][j] > A[i][j - 1]) { A[i][j] = A[i - 1][j]; @@ -52,12 +62,16 @@ for (i = 0; i <= m; i++) { A[i][j] = A[i][j - 1]; } + // visualize { tracer3.deselect(i - 1, j); tracer3.deselect(i, j - 1); + // } } + // visualize { tracer3.patch(i, j, A[i][j]); Tracer.delay(); tracer3.depatch(i, j); + // } } } @@ -65,13 +79,17 @@ let finalString = ''; i = m; j = n; while (i >= 1 && j >= 1) { + // visualize { tracer3.select(i, j); Tracer.delay(); + // } if (string1[i - 1] === string2[j - 1]) { + // visualize { tracer1.select(i - 1); Tracer.delay(); tracer2.select(j - 1); Tracer.delay(); + // } finalString = string1[i - 1] + finalString; i--; @@ -83,5 +101,7 @@ while (i >= 1 && j >= 1) { } } +// logger { logger.println(`Longest Common Subsequence Length is ${A[m][n]}`); logger.println(`Longest Common Subsequence is ${finalString}`); +// } diff --git a/Dynamic Programming/Longest Increasing Subsequence/code.js b/Dynamic Programming/Longest Increasing Subsequence/code.js index cfc13fc0..1cc46e40 100644 --- a/Dynamic Programming/Longest Increasing Subsequence/code.js +++ b/Dynamic Programming/Longest Increasing Subsequence/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,35 +10,50 @@ const A = Randomize.Array1D({ N: 10, value: () => Randomize.Integer({ min: 0, ma const LIS = new Array(A.length); tracer.set(A); Tracer.delay(); +// } // Initialize LIS values for all indexes for (let i = 0; i < A.length; i++) { LIS[i] = 1; } +// logger { logger.println('Calculating Longest Increasing Subsequence values in bottom up manner '); +// } // Compute optimized LIS values in bottom up manner for (let i = 1; i < A.length; i++) { + // visualize { tracer.select(i); logger.println(` LIS[${i}] = ${LIS[i]}`); + // } for (let j = 0; j < i; j++) { + // visualize { tracer.patch(j); Tracer.delay(); tracer.depatch(j); + // } if (A[i] > A[j] && LIS[i] < LIS[j] + 1) { LIS[i] = LIS[j] + 1; + // logger { logger.println(` LIS[${i}] = ${LIS[i]}`); + // } } } + // visualize { tracer.deselect(i); + // } } // Pick maximum of all LIS values +// logger { logger.println('Now calculate maximum of all LIS values '); +// } let max = LIS[0]; for (let i = 1; i < A.length; i++) { if (max < LIS[i]) { max = LIS[i]; } } +// logger { logger.println(`Longest Increasing Subsequence = max of all LIS = ${max}`); +// } diff --git a/Dynamic Programming/Longest Palindromic Subsequence/code.js b/Dynamic Programming/Longest Palindromic Subsequence/code.js index 42b67224..1e7de776 100644 --- a/Dynamic Programming/Longest Palindromic Subsequence/code.js +++ b/Dynamic Programming/Longest Palindromic Subsequence/code.js @@ -1,9 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); - -const tracer = new Array1DTracer('Input Text'); -const matrix = new Array2DTracer('Matrix'); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, matrix, logger])); +// } const seq = 'BBABCBCAB'; let N; @@ -20,9 +17,15 @@ for (i = 0; i < N; i++) { L[i][i] = 1; } +// define tracer variables { +const tracer = new Array1DTracer('Input Text'); +const matrix = new Array2DTracer('Matrix'); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, matrix, logger])); tracer.set(seq); matrix.set(L); Tracer.delay(); +// } function max(a, b) { if (a > b) { @@ -31,56 +34,81 @@ function max(a, b) { return b; } +// logger { logger.println('LPS for any string with length = 1 is 1'); +// } for (i = 2; i <= N; i++) { + // logger { logger.println('--------------------------------------------------'); logger.println(`Considering a sub-string of length ${i}`); logger.println('--------------------------------------------------'); + // } for (j = 0; j < N - i + 1; j++) { const k = j + i - 1; + // visualize { tracer.select(j); Tracer.delay(); tracer.patch(k); Tracer.delay(); + // } + // logger { logger.println(`Comparing ${seq[j]} and ${seq[k]}`); + // } if (seq[j] === seq[k] && i === 2) { + // logger { logger.println(`They are equal and size of the string in the interval${j} to ${k} is 2, so the Longest Palindromic Subsequence in the Given range is 2`); + // } + // visualize { matrix.patch(j, k); Tracer.delay(); + // } L[j][k] = 2; + // visualize { matrix.set(L); matrix.depatch(j, k); Tracer.delay(); + // } } else if (seq[j] === seq[k]) { + // logger { logger.println(`They are equal, so the Longest Palindromic Subsequence in the Given range is 2 + the Longest Increasing Subsequence between the indices ${j + 1} to ${k - 1}`); + // } + // visualize { matrix.patch(j, k); Tracer.delay(); matrix.select(j + 1, k - 1); Tracer.delay(); + // } L[j][k] = L[j + 1][k - 1] + 2; + // visualize { matrix.set(L); matrix.depatch(j, k); Tracer.delay(); matrix.deselect(j + 1, k - 1); Tracer.delay(); + // } } else { + // logger { logger.println(`They are NOT equal, so the Longest Palindromic Subsequence in the Given range is the maximum Longest Increasing Subsequence between the indices ${j + 1} to ${k} and ${j} to ${k - 1}`); + // } + // visualize { matrix.patch(j, k); Tracer.delay(); matrix.select(j + 1, k); Tracer.delay(); matrix.select(j, k - 1); Tracer.delay(); + // } L[j][k] = max(L[j + 1][k], L[j][k - 1]); + // visualize { matrix.set(L); matrix.depatch(j, k); @@ -89,12 +117,19 @@ for (i = 2; i <= N; i++) { Tracer.delay(); matrix.deselect(j, k - 1); Tracer.delay(); + // } } + // logger { logger.println('--------------------------------------------------'); + // } + // visualize { tracer.deselect(j); Tracer.delay(); tracer.depatch(k); Tracer.delay(); + // } } } +// logger { logger.println(`Longest Increasing Subsequence of the given string = L[0][${N - 1}]=${L[0][N - 1]}`); +// } diff --git a/Dynamic Programming/Maximum Subarray/code.js b/Dynamic Programming/Maximum Subarray/code.js index 23bf888f..241f206c 100644 --- a/Dynamic Programming/Maximum Subarray/code.js +++ b/Dynamic Programming/Maximum Subarray/code.js @@ -1,39 +1,60 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +const D = [-2, -3, 4, -1, -2, 1, 5, -3]; + +// define tracer variables { const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); -const D = [-2, -3, 4, -1, -2, 1, 5, -3]; tracer.set(D); Tracer.delay(); +// } const maxSubarraySum = (function maxSubarray(array) { let maxSoFar = 0; let maxEndingHere = 0; + // logger { logger.println('Initializing maxSoFar = 0 & maxEndingHere = 0'); + // } for (let i = 0; i < array.length; i++) { + // visualize { tracer.select(i); + // } + // logger { logger.println(`${maxEndingHere} + ${array[i]}`); + // } maxEndingHere += array[i]; + // logger { logger.println(`=> ${maxEndingHere}`); + // } if (maxEndingHere < 0) { + // logger { logger.println('maxEndingHere is negative, set to 0'); + // } maxEndingHere = 0; } if (maxSoFar < maxEndingHere) { + // logger { logger.println(`maxSoFar < maxEndingHere, setting maxSoFar to maxEndingHere (${maxEndingHere})`); + // } maxSoFar = maxEndingHere; } + // visualize { Tracer.delay(); tracer.deselect(i); + // } } return maxSoFar; }(D)); +// logger { logger.println(`Maximum Subarray's Sum is: ${maxSubarraySum}`); +// } diff --git a/Dynamic Programming/Maximum Sum Path/code.js b/Dynamic Programming/Maximum Sum Path/code.js index 6a267ae1..b95e518e 100644 --- a/Dynamic Programming/Maximum Sum Path/code.js +++ b/Dynamic Programming/Maximum Sum Path/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const D = Randomize.Array2D({ N: 5, M: 5, value: () => Randomize.Integer({ min: 1, max: 5 }) }); const dataViewer = new Array2DTracer(); const tracer = new Array2DTracer('Results Table'); @@ -15,18 +18,21 @@ for (let i = 0; i < D.length; i++) { } tracer.set(DP); Tracer.delay(); +// } const N = DP.length; const M = DP[0].length; function update(i, j, value) { DP[i][j] = value; + // visualize { dataViewer.select(i, j); Tracer.delay(); tracer.patch(i, j, DP[i][j]); Tracer.delay(); tracer.depatch(i, j); dataViewer.deselect(i, j); + // } } for (let i = 0; i < N; i++) { @@ -34,20 +40,34 @@ for (let i = 0; i < N; i++) { if (i === 0 && j === 0) { update(i, j, D[i][j]); } else if (i === 0) { + // visualize { tracer.select(i, j - 1); + // } update(i, j, DP[i][j - 1] + D[i][j]); + // visualize { tracer.deselect(i, j - 1); + // } } else if (j === 0) { + // visualize { tracer.select(i - 1, j); + // } update(i, j, DP[i - 1][j] + D[i][j]); + // visualize { tracer.deselect(i - 1, j); + // } } else { + // visualize { tracer.select(i, j - 1); tracer.select(i - 1, j); + // } update(i, j, Math.max(DP[i][j - 1], DP[i - 1][j]) + D[i][j]); + // visualize { tracer.deselect(i, j - 1); tracer.deselect(i - 1, j); + // } } } } +// logger { logger.println(`max = ${DP[N - 1][M - 1]}`); +// } diff --git a/Dynamic Programming/Pascal's Triangle/code.js b/Dynamic Programming/Pascal's Triangle/code.js index b2e89291..eea8fd7c 100644 --- a/Dynamic Programming/Pascal's Triangle/code.js +++ b/Dynamic Programming/Pascal's Triangle/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 9; const A = new Array(N); @@ -6,32 +8,40 @@ for (let i = N - 1; i >= 0; i--) { A[i] = new Array(N); } +// define tracer variables { const tracer = new Array2DTracer('Pascal\'s Triangle'); Layout.setRoot(new VerticalLayout([tracer])); tracer.set(A); Tracer.delay(); +// } for (let i = 0; i < N; i++) { for (let j = 0; j <= i; j++) { if (j === i || j === 0) { // First and last values in every row are 1 A[i][j] = 1; + // visualize { tracer.patch(i, j, A[i][j]); Tracer.delay(); tracer.depatch(i, j); + // } } else { // Other values are sum of values just above and left of above + // visualize { tracer.select(i - 1, j - 1); Tracer.delay(); tracer.select(i - 1, j); Tracer.delay(); + // } A[i][j] = A[i - 1][j - 1] + A[i - 1][j]; + // visualize { tracer.patch(i, j, A[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.deselect(i - 1, j - 1); tracer.deselect(i - 1, j); + // } } } } diff --git a/Dynamic Programming/Shortest Common Supersequence/code.js b/Dynamic Programming/Shortest Common Supersequence/code.js index d60387c9..7c726fc3 100644 --- a/Dynamic Programming/Shortest Common Supersequence/code.js +++ b/Dynamic Programming/Shortest Common Supersequence/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const string1 = 'AGGTAB'; const string2 = 'GXTXAYB'; @@ -9,6 +11,7 @@ for (let i = 0; i < m + 1; i++) { A[i] = new Array(n + 1); } +// define tracer variables { const tracer1 = new Array1DTracer('String 1'); const tracer2 = new Array1DTracer('String 2'); const tracer3 = new Array2DTracer('Memo Table'); @@ -18,6 +21,7 @@ tracer1.set(string1); tracer2.set(string2); tracer3.set(A); Tracer.delay(); +// } let i; let j; @@ -30,23 +34,29 @@ for (i = 0; i <= m; i++) { } else if (j === 0) { A[i][j] = i; } else if (string1[i - 1] === string2[j - 1]) { + // visualize { tracer1.select(i - 1); Tracer.delay(); tracer2.select(j - 1); Tracer.delay(); tracer3.select(i - 1, j - 1); Tracer.delay(); + // } A[i][j] = A[i - 1][j - 1] + 1; + // visualize { tracer1.deselect(i - 1); tracer2.deselect(j - 1); tracer3.deselect(i - 1, j - 1); + // } } else { + // visualize { tracer3.select(i - 1, j); Tracer.delay(); tracer3.select(i, j - 1); Tracer.delay(); + // } if (A[i - 1][j] < A[i][j - 1]) { A[i][j] = 1 + A[i - 1][j]; @@ -54,13 +64,19 @@ for (i = 0; i <= m; i++) { A[i][j] = 1 + A[i][j - 1]; } + // visualize { tracer3.deselect(i - 1, j); tracer3.deselect(i, j - 1); + // } } + // visualize { tracer3.patch(i, j, A[i][j]); Tracer.delay(); tracer3.depatch(i, j); + // } } } +// logger { logger.println(`Shortest Common Supersequence is ${A[m][n]}`); +// } diff --git a/Dynamic Programming/Sieve of Eratosthenes/code.js b/Dynamic Programming/Sieve of Eratosthenes/code.js index 986a1192..fdac4920 100644 --- a/Dynamic Programming/Sieve of Eratosthenes/code.js +++ b/Dynamic Programming/Sieve of Eratosthenes/code.js @@ -1,6 +1,7 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array1DTracer('Sieve'); const N = 30; const a = []; const b = []; @@ -8,27 +9,41 @@ for (let i = 1; i <= N; i++) { a.push(i); b.push(0); } + +// define tracer variables { +const tracer = new Array1DTracer('Sieve'); tracer.set(a); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); Tracer.delay(); +// } +// visualize { logger.println('1 is not prime'); tracer.select(0); Tracer.delay(); +// } for (let i = 2; i <= N; i++) { if (b[i] === 0) { + // visualize { logger.println(`${i} is not marked, so it is prime`); // a[i-1] is prime mark by red indicators tracer.patch(i - 1); Tracer.delay(); + // } for (let j = i + i; j <= N; j += i) { b[j] = 1; // a[j-1] is not prime, mark by blue indicators + // visualize { logger.println(`${j} is a multiple of ${i} so it is marked as composite`); tracer.select(j - 1); Tracer.delay(); + // } } + // visualize { tracer.depatch(i - 1); + // } } } +// logger { logger.println(`The unmarked numbers are the prime numbers from 1 to ${N}`); +// } diff --git a/Dynamic Programming/Sliding Window/code.js b/Dynamic Programming/Sliding Window/code.js index 60d7212c..7cf9b4ad 100644 --- a/Dynamic Programming/Sliding Window/code.js +++ b/Dynamic Programming/Sliding Window/code.js @@ -1,24 +1,34 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); const D = Randomize.Array1D({ N: 20, value: () => Randomize.Integer({ min: -5, max: 5 }) }); tracer.set(D); Tracer.delay(); +// } let sum = D[0] + D[1] + D[2]; let max = sum; +// visualize { tracer.select(0, 2); logger.println(`sum = ${sum}`); Tracer.delay(); +// } for (let i = 3; i < D.length; i++) { sum += D[i] - D[i - 3]; if (max < sum) max = sum; + // visualize { tracer.deselect(i - 3); tracer.select(i); logger.println(`sum = ${sum}`); Tracer.delay(); + // } } +// visualize { tracer.deselect(D.length - 3, D.length - 1); logger.println(`max = ${max}`); +// } diff --git a/Dynamic Programming/Ugly Numbers/code.js b/Dynamic Programming/Ugly Numbers/code.js index 1f3006b5..356ab7de 100644 --- a/Dynamic Programming/Ugly Numbers/code.js +++ b/Dynamic Programming/Ugly Numbers/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 15; const A = new Array(N); @@ -10,6 +12,7 @@ A[0] = 1; // By convention 1 is an ugly number const M = [2, 3, 5]; // multiples of 2, 3, 5 respectively const I = [0, 0, 0]; // iterators of 2, 3, 5 respectively +// define tracer variables { const tracer = new Array1DTracer('Ugly Numbers'); const tracer2 = new Array1DTracer('Multiples of 2, 3, 5'); const tracer3 = new Array1DTracer(' Iterators I0, I1, I2 '); @@ -19,45 +22,56 @@ tracer.set(A); tracer2.set(M); tracer3.set(I); Tracer.delay(); +// } for (let i = 1; i < N; i++) { // next is minimum of m2, m3 and m5 const next = (M[0] <= M[1]) ? (M[0] <= M[2]) ? M[0] : M[2] : (M[1] <= M[2]) ? M[1] : M[2]; + // logger { logger.println(` Minimum of ${M[0]}, ${M[1]}, ${M[2]} : ${next}`); + // } A[i] = next; + // visualize { tracer.patch(i, A[i]); Tracer.delay(); tracer.depatch(i); + // } if (next === M[0]) { I[0]++; M[0] = A[I[0]] * 2; + // visualize { tracer2.patch(0, M[0]); Tracer.delay(); tracer3.patch(0, I[0]); Tracer.delay(); tracer2.depatch(0); tracer3.depatch(0); + // } } if (next === M[1]) { I[1]++; M[1] = A[I[1]] * 3; + // visualize { tracer2.patch(1, M[1]); Tracer.delay(); tracer3.patch(1, I[1]); Tracer.delay(); tracer2.depatch(1); tracer3.depatch(1); + // } } if (next === M[2]) { I[2]++; M[2] = A[I[2]] * 5; + // visualize { tracer2.patch(2, M[2]); Tracer.delay(); tracer3.patch(2, I[2]); Tracer.delay(); tracer2.depatch(2); tracer3.depatch(2); + // } } } diff --git a/Dynamic Programming/Z String Search/code.js b/Dynamic Programming/Z String Search/code.js index b76cf622..cf831db3 100644 --- a/Dynamic Programming/Z String Search/code.js +++ b/Dynamic Programming/Z String Search/code.js @@ -1,9 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); - -const textTracer = new Array1DTracer('text'); -const pattTracer = new Array1DTracer('pattern'); -const concatTracer = new Array1DTracer('concatenated string'); -const tracer = new Array1DTracer('zArray'); +// } // let pattern = "aab"; // let text = "aabxaabxcaabxaabxay"; @@ -15,13 +12,18 @@ const len = pattern.length + text.length + 1; const z = new Array(len); z[0] = 0; +// define tracer variables { +const textTracer = new Array1DTracer('text'); +const pattTracer = new Array1DTracer('pattern'); +const concatTracer = new Array1DTracer('concatenated string'); +const tracer = new Array1DTracer('zArray'); pattTracer.set(pattern); textTracer.set(text); tracer.set(z); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([textTracer, pattTracer, concatTracer, tracer, logger])); Tracer.delay(); - +// } function createZarr(concat) { let left; @@ -31,19 +33,24 @@ function createZarr(concat) { left = 0; right = 0; for (let i = 1; i < N; i++) { + // visualize { tracer.select(i); Tracer.delay(); + // } if (i > right) { left = right = i; while (right < N && concat[right] === concat[right - left]) { + // visualize { concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is equal to ${concat[right - left]} (at index ${right - left})`); Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); + // } right++; } + // visualize { if (right < N) { concatTracer.patch(right); concatTracer.select(right - left); @@ -52,31 +59,43 @@ function createZarr(concat) { concatTracer.depatch(right); concatTracer.deselect(right - left); } + // } z[i] = (right - left); + // logger { logger.println('--------------------------------'); logger.println(`Value of z[${i}] = the length of the substring starting from ${i} which is also the prefix of the concatinated string(=${right - left})`); logger.println('--------------------------------'); + // } right--; } else if (z[i - left] < (right - i + 1)) { + // visualize { logger.println(`The substring from index ${i - left} will not cross the right end.`); concatTracer.patch(right - i + 1); concatTracer.select(i - left); Tracer.delay(); + // } z[i] = z[i - left]; + // visualize { concatTracer.depatch(right - i + 1); concatTracer.deselect(i - left); + // } } else { + // logger { logger.println(`The substring from index ${i - left} will cross the right end.`); + // } left = i; while (right < N && concat[right] === concat[right - left]) { + // visualize { concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is equal to ${concat[right - left]} (at index ${right - left})`); Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); + // } right++; } + // visualize { if (right < N) { concatTracer.patch(right); concatTracer.select(right - left); @@ -85,22 +104,32 @@ function createZarr(concat) { concatTracer.depatch(right); concatTracer.deselect(right - left); } + // } z[i] = (right - left); right--; + // logger { logger.println('--------------------------------'); logger.println(`Value of z[${i}] = the length of the substring starting from ${i} which is also the prefix of the concatinated string(=${right - left})`); logger.println('--------------------------------'); + // } } + // visualize { tracer.deselect(i); tracer.set(z); + // } } } const concat = `${pattern}$${text}`; +// visualize { concatTracer.set(concat); +// } const patLen = pattern.length; createZarr(concat); +// visualize { tracer.set(z); +// } +// logger { logger.println('The Values in Z array equal to the length of the pattern indicates the index at which the pattern is present'); logger.println('==================================='); for (let i = 0; i < len; i++) { @@ -110,3 +139,4 @@ for (let i = 0; i < len; i++) { } } logger.println('==================================='); +// } diff --git "a/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" "b/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" index bcd48952..be6b45af 100644 --- "a/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" +++ "b/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" @@ -1,79 +1,119 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const A = [1, 3, 3, 2, 1, 1, 1]; const N = A.length; +// define tracer variables { const tracer = new Array1DTracer('List of element'); const logger = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(A); Tracer.delay(); +// } function isMajorityElement(element) { let count = 0; + // logger { logger.println(`Verify majority element ${element}`); + // } for (let i = N - 1; i >= 0; i--) { + // visualize { tracer.patch(i, A[i]); Tracer.delay(); + // } if (A[i] === element) { count++; } else { + // visualize { tracer.depatch(i); + // } } } + // logger { logger.println(`Count of our assumed majority element ${count}`); + // } if (count > Math.floor(N / 2)) { + // logger { logger.println('Our assumption was correct!'); + // } return true; } + // logger { logger.println('Our assumption was incorrect!'); + // } return false; } function findProbableElement() { let index = 0; let count = 1; + // visualize { tracer.select(index); Tracer.delay(); + // } + // logger { logger.println(`Beginning with assumed majority element : ${A[index]} count : ${count}`); logger.println('--------------------------------------------------------'); + // } for (let i = 1; i < N; i++) { + // visualize { tracer.patch(i, A[i]); Tracer.delay(); + // } if (A[index] === A[i]) { count++; + // logger { logger.println(`Same as assumed majority element! Count : ${count}`); + // } } else { count--; + // logger { logger.println(`Not same as assumed majority element! Count : ${count}`); + // } } if (count === 0) { + // logger { logger.println('Wrong assumption in majority element'); + // } + // visualize { tracer.deselect(index); tracer.depatch(i); + // } index = i; count = 1; + // visualize { tracer.select(i); Tracer.delay(); + // } + // logger { logger.println(`New assumed majority element!${A[i]} Count : ${count}`); logger.println('--------------------------------------------------------'); + // } } else { + // visualize { tracer.depatch(i); + // } } } + // logger { logger.println(`Finally assumed majority element ${A[index]}`); logger.println('--------------------------------------------------------'); + // } return A[index]; } function findMajorityElement() { const element = findProbableElement(); + // logger { if (isMajorityElement(element) === true) { logger.println(`Majority element is ${element}`); } else { logger.println('No majority element'); } + // } } findMajorityElement(); diff --git a/Greedy/Dijkstra's Shortest Path/code.js b/Greedy/Dijkstra's Shortest Path/code.js index d0a57ad9..3cafa918 100644 --- a/Greedy/Dijkstra's Shortest Path/code.js +++ b/Greedy/Dijkstra's Shortest Path/code.js @@ -1,17 +1,22 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); +const MAX_VALUE = Infinity; +const S = []; // S[end] returns the distance from start node to end node +for (let i = 0; i < G.length; i++) S[i] = MAX_VALUE; + +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const tracerS = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, tracerS, logger])); tracer.log(logger); -const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); -const MAX_VALUE = Infinity; -const S = []; // S[end] returns the distance from start node to end node -for (let i = 0; i < G.length; i++) S[i] = MAX_VALUE; tracerS.set(S); Tracer.delay(); +// } function Dijkstra(start, end) { let minIndex; @@ -19,10 +24,12 @@ function Dijkstra(start, end) { const D = []; // D[i] indicates whether the i-th node is discovered or not for (let i = 0; i < G.length; i++) D.push(false); S[start] = 0; // Starting node is at distance 0 from itself + // visualize { tracerS.patch(start, S[start]); Tracer.delay(); tracerS.depatch(start); tracerS.select(start); + // } let k = G.length; while (k--) { // Finding a node with the shortest distance from S[minIndex] @@ -35,30 +42,38 @@ function Dijkstra(start, end) { } if (minDistance === MAX_VALUE) break; // If there is no edge from current node, jump out of loop D[minIndex] = true; + // visualize { tracerS.select(minIndex); tracer.visit(minIndex); Tracer.delay(); + // } // For every unvisited neighbour of current node, we check // whether the path to it is shorter if going over the current node for (let i = 0; i < G.length; i++) { if (G[minIndex][i] && S[i] > S[minIndex] + G[minIndex][i]) { S[i] = S[minIndex] + G[minIndex][i]; + // visualize { tracerS.patch(i, S[i]); tracer.visit(i, minIndex, S[i]); Tracer.delay(); tracerS.depatch(i); tracer.leave(i, minIndex); Tracer.delay(); + // } } } + // visualize { tracer.leave(minIndex); Tracer.delay(); + // } } + // logger { if (S[end] === MAX_VALUE) { logger.println(`there is no path from ${start} to ${end}`); } else { logger.println(`the shortest path from ${start} to ${end} is ${S[end]}`); } + // } } const s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node @@ -66,6 +81,8 @@ let e; // e = end node do { e = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (s === e); +// logger { logger.println(`finding the shortest path from ${s} to ${e}`); Tracer.delay(); +// } Dijkstra(s, e); diff --git a/Greedy/Job Scheduling Problem/code.js b/Greedy/Job Scheduling Problem/code.js index d8888165..4192792d 100644 --- a/Greedy/Job Scheduling Problem/code.js +++ b/Greedy/Job Scheduling Problem/code.js @@ -1,16 +1,11 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const jobId = ['a', 'b', 'c', 'd', 'e']; const deadline = [2, 1, 2, 1, 3]; const profit = [100, 19, 27, 25, 15]; const N = deadline.length; - -const tracer3 = new Array1DTracer('Schedule'); -const tracer = new Array1DTracer('Job Ids'); -const tracer1 = new Array1DTracer('Deadlines'); -const tracer2 = new Array1DTracer('Profit'); -Layout.setRoot(new VerticalLayout([tracer3, tracer, tracer1, tracer2])); - // sort according to decreasing order of profit // Bubble sort implemented ... Implement a better algorithm for better performance for (let i = 0; i < N - 1; i++) { @@ -34,11 +29,19 @@ const result = new Array(N); for (let i = N - 1; i >= 0; i--) { result[i] = '-'; } + +// define tracer variables { +const tracer3 = new Array1DTracer('Schedule'); +const tracer = new Array1DTracer('Job Ids'); +const tracer1 = new Array1DTracer('Deadlines'); +const tracer2 = new Array1DTracer('Profit'); +Layout.setRoot(new VerticalLayout([tracer3, tracer, tracer1, tracer2])); tracer.set(jobId); tracer1.set(deadline); tracer2.set(profit); tracer3.set(result); Tracer.delay(); +// } // Initialise all slots to free for (let i = 0; i < N; i++) { @@ -51,21 +54,29 @@ for (let i = 0; i < N; i++) { Start from the last possible slot. Find a slot for the job */ + // visualize { tracer.select(i); Tracer.delay(); tracer1.select(i); Tracer.delay(); + // } for (let j = Math.min(N, deadline[i]) - 1; j >= 0; j--) { if (slot[j] === 0) { + // visualize { tracer3.patch(j, jobId[i]); Tracer.delay(); + // } result[j] = jobId[i]; slot[j] = 1; + // visualize { tracer3.depatch(j); + // } break; } } + // visualize { tracer.deselect(i); tracer1.deselect(i); + // } } diff --git a/Greedy/Kruskal's Minimum Spanning Tree/code.js b/Greedy/Kruskal's Minimum Spanning Tree/code.js index 77b9ff6a..8cc2535e 100644 --- a/Greedy/Kruskal's Minimum Spanning Tree/code.js +++ b/Greedy/Kruskal's Minimum Spanning Tree/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -13,6 +16,7 @@ Layout.setRoot(new VerticalLayout([tracer, logger])); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function kruskal() { const vcount = G.length; @@ -40,12 +44,16 @@ function kruskal() { let wsum = 0; for (let n = 0; n < vcount - 1 && edges.length > 0;) { const e = edges.shift(); // Get the edge of min weight + // visualize { tracer.visit(e[0], e[1]); Tracer.delay(); + // } if (t[e[0]] === t[e[1]]) { // e[0] & e[1] already in the same tree, ignore + // visualize { tracer.leave(e[0], e[1]); Tracer.delay(); + // } continue; } @@ -61,7 +69,9 @@ function kruskal() { n += 1; } + // logger { logger.println(`The sum of all edges is: ${wsum}`); + // } } kruskal(); diff --git a/Greedy/Prim's Minimum Spanning Tree/code.js b/Greedy/Prim's Minimum Spanning Tree/code.js index e44458fc..107f0144 100644 --- a/Greedy/Prim's Minimum Spanning Tree/code.js +++ b/Greedy/Prim's Minimum Spanning Tree/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -14,6 +17,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 10, ratio: .4, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function prim() { // Finds a tree so that there exists a path between @@ -33,8 +37,10 @@ function prim() { { for (let j = 0; j < G.length; j++) { if (!D[j] && G[i][j]) { + // visualize { tracer.visit(i, j); Tracer.delay(); + // } // Second node must not be visited and must be connected to first node if (G[i][j] < minD) { // Searching for cheapest edge which satisfies requirements @@ -42,19 +48,27 @@ function prim() { minI = i; minJ = j; } + // visualize { tracer.leave(i, j); Tracer.delay(); + // } } } } } + // visualize { tracer.visit(minI, minJ); Tracer.delay(); + // } D[minJ] = 1; // Visit second node and insert it into or tree sum += G[minI][minJ]; } + // logger { logger.println(`The sum of all edges is: ${sum}`); + // } } +// logger { logger.println('nodes that belong to minimum spanning tree are: '); +// } prim(); diff --git a/Greedy/Stable Matching/code.js b/Greedy/Stable Matching/code.js index 1c15579e..40369cf2 100644 --- a/Greedy/Stable Matching/code.js +++ b/Greedy/Stable Matching/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const ARank = { Flavio: ['Valentine', 'July', 'Summer', 'Violet'], @@ -14,6 +16,7 @@ const BRank = { Summer: ['Stephen', 'Flavio', 'Albert', 'Jack'], }; +// define tracer variables { const tracerA = new Array1DTracer('A'); const tracerB = new Array1DTracer('B'); @@ -25,6 +28,7 @@ tracerB.set(_bKeys); const logTracer = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracerA, tracerB, logTracer])); Tracer.delay(); +// } function init(rank) { const o = {}; @@ -51,44 +55,58 @@ const B = init(BRank); let a; while ((a = extractUnstable(A))) { + // logger { logTracer.println(`Selecting ${a.key}`); Tracer.delay(); + // } const bKey = a.rankKeys.shift(); const b = B[bKey]; + // logger { logTracer.println(`--> Choicing ${b.key}`); Tracer.delay(); + // } if (b.stable === false) { + // logger { logTracer.println(`--> ${b.key} is not stable, stabilizing with ${a.key}`); Tracer.delay(); + // } a.stable = b; b.stable = a; + // visualize { tracerA.select(_aKeys.indexOf(a.key)); Tracer.delay(); tracerB.select(_bKeys.indexOf(b.key)); Tracer.delay(); + // } } else { const rankAinB = b.rankKeys.indexOf(a.key); const rankPrevAinB = b.rankKeys.indexOf(b.stable.key); if (rankAinB < rankPrevAinB) { + // logger { logTracer.println(`--> ${bKey} is more stable with ${a.key} rather than ${b.stable.key} - stabilizing again`); Tracer.delay(); + // } A[b.stable.key].stable = false; + // visualize { tracerA.deselect(_aKeys.indexOf(b.stable.key)); Tracer.delay(); + // } a.stable = b; b.stable = a; + // visualize { tracerA.select(_aKeys.indexOf(a.key)); Tracer.delay(); tracerB.select(_bKeys.indexOf(b.key)); Tracer.delay(); + // } } } } diff --git a/Simple Recursive/Cellular Automata/code.js b/Simple Recursive/Cellular Automata/code.js index c65f1954..58246d56 100644 --- a/Simple Recursive/Cellular Automata/code.js +++ b/Simple Recursive/Cellular Automata/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const gridSize = 10; const generations = 4; @@ -18,11 +20,15 @@ for (let i = 0; i < gridSize; i++) { nextG[i][j] = '#'; } } + +// define tracer variables { const tracer = new Array2DTracer(); Layout.setRoot(new VerticalLayout([tracer])); tracer.set(G); Tracer.delay(); +// } +// visualize { for (let gi = 0; gi < G.length; gi++) { for (let gj = 0; gj < G[gi].length; gj++) { if (G[gi][gj] === '#') { @@ -30,6 +36,7 @@ for (let gi = 0; gi < G.length; gi++) { } } } +// } function CellularAutomata(fillShape, emptyShape) { const nextGrid = []; @@ -70,10 +77,13 @@ function CellularAutomata(fillShape, emptyShape) { for (let i = 0; i < nextGrid.length; i++) { for (let j = 0; j < nextGrid[i].length; j++) { + // visualize { tracer.depatch(i, j, G[i][j]); tracer.select(i, j); Tracer.delay(); + // } G[i][j] = nextGrid[i][j]; + // visualize { if (G[i][j] === fillShape) { tracer.patch(i, j, G[i][j]); } else { @@ -81,6 +91,7 @@ function CellularAutomata(fillShape, emptyShape) { tracer.depatch(i, j, G[i][j]); tracer.deselect(i, j); } + // } } } } diff --git a/Simple Recursive/Euclidean Greatest Common Divisor/code.js b/Simple Recursive/Euclidean Greatest Common Divisor/code.js index 7f7dc53c..3419978f 100644 --- a/Simple Recursive/Euclidean Greatest Common Divisor/code.js +++ b/Simple Recursive/Euclidean Greatest Common Divisor/code.js @@ -1,42 +1,63 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array1DTracer('Euclidean Algorithm'); const a = []; a.push(465); a.push(255); + +// define tracer variables { +const tracer = new Array1DTracer('Euclidean Algorithm'); tracer.set(a); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); Tracer.delay(); +// } +// logger { logger.println(`Finding the greatest common divisor of ${a[0]} and ${a[1]}`); logger.println('Checking if first number is at most the second number'); +// } if (a[0] > a[1]) { const tmp = a[0]; a[0] = a[1]; a[1] = tmp; + // logger { logger.println('The first number is bigger than the second number. Switching the numbers.'); + // } + // visualize { tracer.set(a); Tracer.delay(); + // } } while (a[0] > 0) { + // logger { logger.println(`${a[1]} % ${a[0]} = ${a[1] % a[0]}`); logger.println('Switching a[1] with a[1]%a[0]'); + // } a[1] %= a[0]; + // visualize { tracer.patch(1, a[1]); Tracer.delay(); + // } + // logger { logger.println('Now switching the two values to keep a[0] < a[1]'); + // } const tmp = a[0]; a[0] = a[1]; a[1] = tmp; + // visualize { tracer.patch(0, a[0]); tracer.patch(1, a[1]); Tracer.delay(); tracer.depatch(0); tracer.depatch(1); + // } } +// logger { logger.println(`The greatest common divisor is ${a[1]}`); +// } diff --git a/Simple Recursive/Suffix Array/code.js b/Simple Recursive/Suffix Array/code.js index 6ddf49b4..dc0c0261 100644 --- a/Simple Recursive/Suffix Array/code.js +++ b/Simple Recursive/Suffix Array/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } let word = 'virgo'; const suffixArray = (function skeleton(word) { @@ -11,6 +13,7 @@ const suffixArray = (function skeleton(word) { return arr; }(word)); +// define tracer variables { const saTracer = new Array2DTracer('Suffix Array'); const wordTracer = new Array1DTracer('Given Word'); const logger = new LogTracer('Progress'); @@ -19,24 +22,35 @@ Layout.setRoot(new VerticalLayout([saTracer, wordTracer, logger])); saTracer.set(suffixArray); wordTracer.set(word); Tracer.delay(); +// } word += '$'; // special character +// logger { logger.println('Appended \'$\' at the end of word as terminating (special) character. Beginning filling of suffixes'); +// } function selectSuffix(word, i) { let c = i; while (i < word.length - 1) { + // visualize { wordTracer.select(i); + // } i++; } + // visualize { Tracer.delay(); + // } while (c < word.length - 1) { + // visualize { wordTracer.deselect(c); + // } c++; } + // visualize { Tracer.delay(); + // } } (function createSA(sa, word) { @@ -44,19 +58,26 @@ function selectSuffix(word, i) { sa[i][1] = word.slice(i); selectSuffix(word, i); + // visualize { saTracer.patch(i, 1, sa[i][1]); Tracer.delay(); saTracer.depatch(i, 1); Tracer.delay(); + // } } }(suffixArray, word)); +// logger { logger.println('Re-organizing Suffix Array in sorted order of suffixes using efficient sorting algorithm (O(N.log(N)))'); +// } suffixArray.sort((a, b) => { + // logger { logger.println(`The condition a [1] (${a[1]}) > b [1] (${b[1]}) is ${a[1] > b[1]}`); + // } return a[1] > b[1]; }); +// visualize { for (let i = 0; i < word.length; i++) { saTracer.patch(i, 0, suffixArray[i][0]); saTracer.patch(i, 1, suffixArray[i][1]); @@ -65,3 +86,4 @@ for (let i = 0; i < word.length; i++) { saTracer.depatch(i, 0); saTracer.depatch(i, 1); } +// } diff --git a/Uncategorized/Affine Cipher/code.js b/Uncategorized/Affine Cipher/code.js index 934b6f6e..55bc0349 100644 --- a/Uncategorized/Affine Cipher/code.js +++ b/Uncategorized/Affine Cipher/code.js @@ -1,6 +1,10 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const plainText = 'secret'; + +// define tracer variables { const ptTracer = new Array1DTracer('Encryption'); const ctTracer = new Array1DTracer('Decryption'); const logger = new LogTracer(); @@ -8,6 +12,7 @@ Layout.setRoot(new VerticalLayout([ptTracer, ctTracer, logger])); ptTracer.set(plainText); Tracer.delay(); +// } /* code assumes that plainText contains ONLY LOWER CASE ALPHABETS @@ -27,26 +32,34 @@ function encrypt(plainText) { const index = alpha.charCodeAt(0) - 'a'.charCodeAt(0); let result = ((keys.a * index) + keys.b).mod(N); + // logger { logger.println(`Index of ${alpha} = ${index}`); + // } result += 'a'.charCodeAt(0); return String.fromCharCode(result); } + // logger { logger.println('Beginning Affine Encryption'); logger.println('Encryption formula: ((keys.a * indexOfAlphabet) + keys.b) % N'); logger.println(`keys.a=${keys.a}, keys.b=${keys.b}, N=${N}`); + // } for (const i in plainText) { + // visualize { ptTracer.select(i); Tracer.delay(); ptTracer.deselect(i); + // } cypherText += cryptAlpha(plainText[i]); + // visualize { ptTracer.patch(i, cypherText.slice(-1)); Tracer.delay(); ptTracer.depatch(i); + // } } return cypherText; @@ -62,34 +75,44 @@ function decrypt(cypherText) { } })()); + // logger { logger.println(`a-1 = ${aInverse}`); + // } function decryptAlpha(alpha) { const index = alpha.charCodeAt(0) - 'a'.charCodeAt(0); let result = (aInverse * (index - keys.b)).mod(N); + // logger { logger.println(`Index of ${alpha} = ${index}`); + // } result += 'a'.charCodeAt(0); return String.fromCharCode(result); } + // logger { logger.println('Beginning Affine Decryption'); logger.println('Decryption formula: (a-1 * (index - keys.b)) % N'); logger.println(`keys.b=${keys.b}, N=${N}`); + // } for (const i in cypherText) { + // visualize { ctTracer.select(i); Tracer.delay(); ctTracer.deselect(i); Tracer.delay(); + // } plainText += decryptAlpha(cypherText[i]); + // visualize { ctTracer.patch(i, plainText.slice(-1)); Tracer.delay(); ctTracer.depatch(i); Tracer.delay(); + // } } return plainText; diff --git a/Uncategorized/Caesar Cipher/code.js b/Uncategorized/Caesar Cipher/code.js index 4edf6f16..b2c60e09 100644 --- a/Uncategorized/Caesar Cipher/code.js +++ b/Uncategorized/Caesar Cipher/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const string = 'hello! how are you doing?'; const rotation = 5; @@ -11,6 +13,7 @@ const alphabetMap = alphabet.split('').reduce((map, curr, idx) => { return map; }, {}); +// define tracer variables { const encryptTracer = new Array1DTracer('Encryption'); const decryptTracer = new Array1DTracer('Decryption'); const logger = new LogTracer(); @@ -18,6 +21,7 @@ Layout.setRoot(new VerticalLayout([encryptTracer, decryptTracer, logger])); encryptTracer.set(string); Tracer.delay(); +// } function getPosUp(pos) { return (pos === alphabet.length - 1) ? 0 : pos + 1; @@ -32,7 +36,9 @@ function getNextChar(currChar, direction) { const nextPos = direction === 'up' ? getPosUp(pos) : getPosDown(pos); const nextChar = alphabet.charAt(nextPos); + // logger { logger.println(`${currChar} -> ${nextChar}`); + // } return nextChar; } @@ -40,45 +46,65 @@ function cipher(str, rotation, direction, cipherTracer) { if (!str) return ''; for (let i = 0; i < str.length; i++) { + // visualize { Tracer.delay(); + // } let currChar = str.charAt(i); if (typeof alphabetMap[currChar] === 'number') { // don't encrpt/decrypt characters not in alphabetMap let r = rotation; + // logger { logger.println(`Rotating ${currChar} ${direction} ${rotation} times`); + // } + // visualize { cipherTracer.select(i); Tracer.delay(); + // } // perform given amount of rotations in the given direction while (r-- > 0) { currChar = getNextChar(currChar, direction); + // visualize { cipherTracer.patch(i, currChar); Tracer.delay(); + // } } } else { + // logger { logger.println('Ignore this character'); + // } } str = str.substring(0, i) + currChar + str.substring(i + 1); + // logger { logger.println(`Current result: ${str}`); + // } } return str; } function encrypt(str, rotation) { + // logger { logger.println(`Encrypting: ${str}`); + // } return cipher(str, rotation, 'up', encryptTracer); } function decrypt(str, rotation) { + // logger { logger.println(`Decrypting: ${str}`); + // } return cipher(str, rotation, 'down', decryptTracer); } const encrypted = encrypt(string, rotation); +// logger { logger.println(`Encrypted result: ${encrypted}`); +// } decryptTracer.set(encrypted); const decrypted = decrypt(encrypted, rotation); +// logger { logger.println(`Decrypted result: ${decrypted}`); +// } diff --git a/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js b/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js index b2afff6c..86fce896 100644 --- a/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js +++ b/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js @@ -1,9 +1,12 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const A = [[2, 3], [3, 4]]; const B = [[1, 0], [1, 2]]; const C = [[6, 5], [8, 7]]; +// define tracer variables { const matrixATracer = new Array2DTracer('Matrix A'); const matrixBTracer = new Array2DTracer('Matrix B'); const matrixCTracer = new Array2DTracer('Matrix C'); @@ -15,6 +18,7 @@ matrixATracer.set(A); matrixBTracer.set(B); matrixCTracer.set(C); Tracer.delay(); +// } function FreivaldsAlgorithm() { let k = 5; @@ -26,7 +30,9 @@ function FreivaldsAlgorithm() { const n = A.length; while (k--) { + // logger { logger.println(`Iterations remained: #${k}`); + // } // Generate random vector const r = []; @@ -36,8 +42,10 @@ function FreivaldsAlgorithm() { P.push(-1); r.push((Math.random() < 0.5) << 0); } + // visualize { randomVectorTracer.set(r); Tracer.delay(); + // } // Compute Br, Cr const Br = []; @@ -63,17 +71,23 @@ function FreivaldsAlgorithm() { } P.push(tmp); } + // visualize { resultVectorTracer.set(P); Tracer.delay(); + // } for (i = 0; i < n; i++) { if (P[i] !== 0) { + // logger { logger.println(`P[${i}] !== 0 (${P[i]}), exit`); + // } return false; } } + // logger { logger.println('Result vector is identity, continue...'); + // } } return true; diff --git a/Uncategorized/Magic Square/code.js b/Uncategorized/Magic Square/code.js index 88f62f5c..912f52d9 100644 --- a/Uncategorized/Magic Square/code.js +++ b/Uncategorized/Magic Square/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const n = 7; const A = new Array(n); @@ -12,51 +14,67 @@ for (let i = n - 1; i >= 0; i--) { } } +// define tracer variables { const tracer = new Array2DTracer('Magic Square'); const logTracer = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracer, logTracer])); tracer.set(A); Tracer.delay(); +// } let i = Math.floor(n / 2); let j = n - 1; for (let num = 1; num <= n * n;) { + // logger { logTracer.println(`i = ${i}`); logTracer.println(`j = ${j}`); + // } if (i === -1 && j === n) { j = n - 2; i = 0; + // logger { logTracer.println('Changing : '); logTracer.println(`i = ${i}`); logTracer.println(`j = ${j}`); + // } } else { if (j === n) { j = 0; + // logger { logTracer.println(`Changing : j = ${j}`); + // } } if (i < 0) { i = n - 1; + // logger { logTracer.println(`Changing : i = ${i}`); + // } } } if (A[i][j] > 0) { + // logger { logTracer.println(`Cell already filled : Changing i = ${i} j = ${j}`); + // } j -= 2; i++; } else { A[i][j] = num++; + // visualize { tracer.patch(i, j, A[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.select(i, j); Tracer.delay(); + // } j++; i--; } } +// logger { logTracer.println(`Magic Constant is ${n * (n * n + 1) / 2}`); +// } diff --git a/Uncategorized/Maze Generation/code.js b/Uncategorized/Maze Generation/code.js index 835c62b1..223753ef 100644 --- a/Uncategorized/Maze Generation/code.js +++ b/Uncategorized/Maze Generation/code.js @@ -1,8 +1,7 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array2DTracer(); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); const n = 6; // rows (change these!) const m = 6; // columns (change these!) @@ -56,8 +55,13 @@ for (let i = 0; i < vEnd; i++) { // by row } } +// define tracer variables { +const tracer = new Array2DTracer(); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); Tracer.delay(); +// } function buildMaze() { const mySet = new disjointSet(); @@ -73,7 +77,9 @@ function buildMaze() { mySet.addElements(width * height); + // logger { logger.println('initializing grid (all walls are up)'); + // } // init 'graph' // each room has two walls, a down and right wall. for (let i = 0; i < width; i++) { @@ -91,7 +97,9 @@ function buildMaze() { G[j * 2 + 1][i * 3 + 1] = locationString[0]; G[j * 2 + 1][i * 3 + 2] = locationString[1]; + // visualize { tracer.set(G); + // } } rightWalls.push({ x: i, y: j }); @@ -100,7 +108,9 @@ function buildMaze() { } } + // logger { logger.println('shuffled the walls for random selection'); + // } // Randomly shuffle the walls shuffle(rightWalls); shuffle(downWalls); @@ -117,26 +127,34 @@ function buildMaze() { if (iYdown < height) { const u = graph[iX][iY]; const v = graph[iX][iYdown]; + // visualize { tracer.patch(iY * 2 + 1, iX * 3 + 1); tracer.patch(iY * 2 + 1, iX * 3 + 2); tracer.patch(iYdown * 2 + 1, iX * 3 + 1); tracer.patch(iYdown * 2 + 1, iX * 3 + 2); + // } if (mySet.find(u) !== mySet.find(v)) { + // logger { logger.println(`Rooms: ${u} & ${v} now belong to the same set, delete wall between them`); Tracer.delay(); + // } mySet.setUnion(u, v); setSize++; // delete wall walls[u].down = false; } else { + // logger { logger.println(`Rooms: ${u} & ${v} would create a cycle! This is not good!`); Tracer.delay(); + // } } + // visualize { tracer.depatch(iY * 2 + 1, iX * 3 + 1); tracer.depatch(iY * 2 + 1, iX * 3 + 2); tracer.depatch(iYdown * 2 + 1, iX * 3 + 1); tracer.depatch(iYdown * 2 + 1, iX * 3 + 2); + // } } } else if (randomWall === 2 && rightWalls.length > 0) { // Right Wall @@ -147,31 +165,41 @@ function buildMaze() { if (iXright < width) { const u = graph[iX][iY]; const v = graph[iXright][iY]; + // visualize { tracer.patch(iY * 2 + 1, iX * 3 + 1); tracer.patch(iY * 2 + 1, iX * 3 + 2); tracer.patch(iY * 2 + 1, iXright * 3 + 1); tracer.patch(iY * 2 + 1, iXright * 3 + 2); + // } if (mySet.find(u) !== mySet.find(v)) { + // logger { logger.println(`Rooms: ${u} & ${v} now belong to the same set, delete wall between them`); Tracer.delay(); + // } mySet.setUnion(u, v); setSize++; // delete wall walls[u].right = false; } else { + // logger { logger.println(`Rooms: ${u} & ${v} would create a cycle! This is not good!`); Tracer.delay(); + // } } + // visualize { tracer.depatch(iY * 2 + 1, iX * 3 + 1); tracer.depatch(iY * 2 + 1, iX * 3 + 2); tracer.depatch(iY * 2 + 1, iXright * 3 + 1); tracer.depatch(iY * 2 + 1, iXright * 3 + 2); + // } } } } + // logger { logger.println('deleting the walls'); + // } // update deleted walls for (let i = 0; i < width; i++) { for (let j = 0; j < height; j++) { @@ -180,28 +208,38 @@ function buildMaze() { if (currentWall.down === false) { G[j * 2 + 2][i * 3 + 1] = ' '; G[j * 2 + 2][i * 3 + 2] = ' '; + // visualize { tracer.select(j * 2 + 2, i * 3 + 1); Tracer.delay(); tracer.select(j * 2 + 2, i * 3 + 2); Tracer.delay(); + // } } if (currentWall.right === false) { G[j * 2 + 1][i * 3 + 3] = ' '; + // visualize { tracer.select(j * 2 + 1, i * 3 + 3); Tracer.delay(); + // } } + // visualize { tracer.set(G); + // } } } + // logger { logger.println('cleaning up the grid!'); + // } cleanUpGrid(width, height); // Clear out walls for the start and end locations. const randomStart = Math.floor(Math.random() * width); const randomEnd = Math.floor(Math.random() * width); + // logger { logger.println('setting the Start (S) & End (E) locations'); + // } // Start Location G[0][randomStart * 3 + 1] = ' '; @@ -216,10 +254,14 @@ function buildMaze() { cleanUpStartLocation(randomStart); cleanUpEndLocation(randomEnd); + // logger { logger.println('maze is completed!'); + // } // set the data + // visualize { tracer.set(G); + // } } function cleanUpStartLocation(start) { diff --git a/Uncategorized/Miller-Rabin's Primality Test/code.js b/Uncategorized/Miller-Rabin's Primality Test/code.js index 91eec368..50a374e9 100644 --- a/Uncategorized/Miller-Rabin's Primality Test/code.js +++ b/Uncategorized/Miller-Rabin's Primality Test/code.js @@ -1,18 +1,26 @@ +// import visualization libraries { const { Tracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([logger])); Tracer.delay(); +// } for (let i = 0; i < 3; i++) { let a = Math.floor(Math.random() * 300); if (a % 2 === 0) a += 1; testProbablyPrime(a); + // visualize { logger.println('----------'); + // } } testProbablyPrime(151); +// visualize { logger.println('----------'); +// } testProbablyPrime(199, 10); @@ -39,14 +47,20 @@ function power(x, y, p) { * @return {Boolean} */ function testProbablyPrime(n, k = 5) { + // visualize { logger.println(`==> Testing number ${n}`); + // } if (n === 1 || n === 3) { + // visualize { logger.println('==> Simple case, N is 1 or 3'); + // } return true; } if (n % 2 === 0) { + // visualize { logger.println(`==> Simple case, ${n} mod 2 = 0`); + // } return false; } @@ -55,25 +69,35 @@ function testProbablyPrime(n, k = 5) { while (d % 2 === 0) { d /= 2; } + // visualize { logger.println(`d = ${d}`); + // } const P = 100 * (1 - (1 / Math.pow(4, k))); WitnessLoop: do { + // visualize { logger.println(`Remaining iterations: #${k}`); + // } const a = 2 + Math.floor(Math.random() * (n - 4)); + // visualize { logger.println(`--> first test with random = ${a}`); + // } // Compute a^d % n let x = power(a, d, n); if (x === 1 || x === n - 1) { + // visualize { logger.println('--> continue WitnessLoop, x = 1 or x = n-1'); + // } continue; } + // visualize { logger.println('--> second test'); + // } // Keep squaring x while one of the following doesn't // happen @@ -86,20 +110,28 @@ function testProbablyPrime(n, k = 5) { i *= 2; if (x === 1) { + // visualize { logger.println(`--> exiting, ${n} is composite`); + // } return false; } if (x === n - 1) { + // visualize { logger.println('--> continue WitnessLoop'); + // } continue WitnessLoop; } } + // visualize { logger.println(`--> exiting, ${n} is composite 'cause (n-1) is reached`); + // } return false; } while (--k); + // visualize { logger.println(`End of tests, ${n} is probably prime with probabilty of ${P}%`); + // } return true; } From e8d66c6fcf2ec3019629e115c6fffac0db4c80cb Mon Sep 17 00:00:00 2001 From: Jinseo Park Date: Thu, 17 Oct 2019 13:46:51 +0800 Subject: [PATCH 16/26] Fix code folding issue in dfs/tree.js --- Brute Force/Depth-First Search/tree.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Brute Force/Depth-First Search/tree.js b/Brute Force/Depth-First Search/tree.js index a582c529..27dbb865 100644 --- a/Brute Force/Depth-First Search/tree.js +++ b/Brute Force/Depth-First Search/tree.js @@ -27,7 +27,7 @@ Tracer.delay(); // } function DFS(node, parent) { // node = current node, parent = previous node - // visualize {/ + // visualize { tracer.visit(node, parent); Tracer.delay(); // } From 0a096f48801da956b1b5ae1e217e0a0cbcb243a0 Mon Sep 17 00:00:00 2001 From: Dylan Rodriquez Date: Mon, 11 Nov 2019 11:59:40 -0500 Subject: [PATCH 17/26] Improve Knapsack Problem * missing subproblem visualization * error in patch * fixed opt problem patch * Remove unnecessary delays and change unnecessary patch to select --- Dynamic Programming/Knapsack Problem/code.js | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Dynamic Programming/Knapsack Problem/code.js b/Dynamic Programming/Knapsack Problem/code.js index 8fc41c73..21855d03 100644 --- a/Dynamic Programming/Knapsack Problem/code.js +++ b/Dynamic Programming/Knapsack Problem/code.js @@ -17,13 +17,13 @@ for (let i = 0; i < N + 1; i++) { // define tracer variables { const tracer = new Array2DTracer('Knapsack Table'); -const dataViewer1 = new Array1DTracer('Values'); -const dataViewer2 = new Array1DTracer('Weights'); +const valuesTracer = new Array1DTracer('Values'); +const weightsTracer = new Array1DTracer('Weights'); const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, dataViewer1, dataViewer2, logger])); +Layout.setRoot(new VerticalLayout([tracer, valuesTracer, weightsTracer, logger])); tracer.set(DP); -dataViewer1.set(val); -dataViewer2.set(wt); +valuesTracer.set(val); +weightsTracer.set(wt); Tracer.delay(); // } @@ -42,14 +42,13 @@ for (let i = 0; i <= N; i++) { // } } else if (wt[i - 1] <= j) { // take the current item in our collection // visualize { - dataViewer1.select(i - 1); - Tracer.delay(); - dataViewer2.select(i - 1); + weightsTracer.select(i - 1); + valuesTracer.select(i - 1); Tracer.delay(); + tracer.select(i - 1, j - wt[i - 1]); tracer.select(i - 1, j); Tracer.delay(); // } - const A = val[i - 1] + DP[i - 1][j - wt[i - 1]]; const B = DP[i - 1][j]; /* @@ -69,12 +68,13 @@ for (let i = 0; i <= N; i++) { Tracer.delay(); // } } - // visualize { - tracer.deselect(i - 1, j); + // opt subproblem depatch tracer.depatch(i, j); - dataViewer2.deselect(i - 1); - dataViewer1.deselect(i - 1); + tracer.deselect(i - 1, j); + tracer.deselect(i - 1, j - wt[i - 1]); + valuesTracer.deselect(i - 1); + weightsTracer.deselect(i - 1); // } } else { // leave the current item from our collection DP[i][j] = DP[i - 1][j]; From 5cc8741b3917c07029e875829bdcb07119982caa Mon Sep 17 00:00:00 2001 From: frankymacster Date: Thu, 19 Dec 2019 11:59:12 -0500 Subject: [PATCH 18/26] Add Shortest Unsorted Continous Subarray (#20) --- .../README.md | 11 ++ .../code.js | 144 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 Uncategorized/Shortest Unsorted Continuous Subarray/README.md create mode 100644 Uncategorized/Shortest Unsorted Continuous Subarray/code.js diff --git a/Uncategorized/Shortest Unsorted Continuous Subarray/README.md b/Uncategorized/Shortest Unsorted Continuous Subarray/README.md new file mode 100644 index 00000000..26924a03 --- /dev/null +++ b/Uncategorized/Shortest Unsorted Continuous Subarray/README.md @@ -0,0 +1,11 @@ +# Shortest Unsorted Continous Subarray +"Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order, too. + +You need to find the shortest such subarray and output its length." + +## Complexity +* **Time**: worst ![](https://latex.codecogs.com/svg.latex?O(N)), 4 loops are used +* **Space**: worst ![](https://latex.codecogs.com/svg.latex?O(1)), to hold min and max values + +## References +* [LeetCode](https://leetcode.com/articles/shortest-unsorted-continous-subarray/) \ No newline at end of file diff --git a/Uncategorized/Shortest Unsorted Continuous Subarray/code.js b/Uncategorized/Shortest Unsorted Continuous Subarray/code.js new file mode 100644 index 00000000..df0f12c8 --- /dev/null +++ b/Uncategorized/Shortest Unsorted Continuous Subarray/code.js @@ -0,0 +1,144 @@ +// import visualization libraries { + const { Tracer, LogTracer, Array1DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); + // } + + // define tracer variables { + const tracer = new Array1DTracer('Sequence'); + const D = [2, 6, 4, 8, 10, 9, 15]; + tracer.set(D); + const logger = new LogTracer(); + Layout.setRoot(new VerticalLayout([tracer, logger])); + Tracer.delay(); + // } + + function findUnsortedSubarray(nums) { + let min = Number.MAX_VALUE; + let max = Number.MIN_VALUE; + let flag = false; + // visualize { + let minIndex = -1; + let maxIndex = -1; + // } + + for (let i = 1; i < nums.length; i++) { + // visualize { + tracer.deselect(i - 2, i - 1); + tracer.select(i - 1, i); + Tracer.delay(); + // } + + if (nums[i] < nums[i - 1]) { + flag = true; + } + if (flag) { + min = Math.min(min, nums[i]); + // visualize { + if (min === nums[i]) { + tracer.depatch(minIndex); + minIndex = i; + tracer.patch(i); + } + Tracer.delay(); + // } + } + } + + // visualize { + tracer.depatch(minIndex); + tracer.deselect(nums.length - 2); + tracer.deselect(nums.length - 1); + // } + + // logger { + logger.println(`min = ${min}`); + Tracer.delay(); + // } + + flag = false; + for (let i = nums.length - 2; i >= 0; i--) { + // visualize { + tracer.deselect(i + 1, i + 2); + tracer.select(i, i + 1); + Tracer.delay(); + // } + + if (nums[i] > nums[i + 1]) { + flag = true; + } + if (flag) { + max = Math.max(max, nums[i]); + // visualize { + if (max === nums[i]) { + tracer.depatch(maxIndex); + maxIndex = i; + tracer.patch(i); + } + Tracer.delay(); + // } + } + } + + // visualize { + tracer.depatch(maxIndex); + tracer.deselect(0); + tracer.deselect(1); + Tracer.delay(); + // } + + // logger { + logger.println(`max = ${max}`); + // } + + let l; + let r; + for (l = 0; l < nums.length; l++) { + // visualize { + tracer.deselect(l - 1); + tracer.select(l); + Tracer.delay(); + // } + + if (min < nums[l]) { + // visualize { + tracer.patch(l); + Tracer.delay(); + // } + break; + } + } + + for (r = nums.length - 1; r >= 0; r--) { + // visualize { + tracer.deselect(r + 1); + tracer.select(r); + Tracer.delay(); + // } + + if (max > nums[r]) { + // visualize { + tracer.patch(r); + Tracer.delay(); + // } + break; + } + } + + // visualize { + tracer.depatch(l); + tracer.depatch(r); + tracer.select(l, r); + Tracer.delay(); + // } + + const result = r - l < 0 + ? 0 + : r - l + 1; + + // logger { + logger.println(`result = ${result}`); + Tracer.delay(); + // } + + return result; + } + findUnsortedSubarray(D); \ No newline at end of file From 145cc57ffde6c01089515764c22e12c3e3045f21 Mon Sep 17 00:00:00 2001 From: frankymacster Date: Thu, 19 Dec 2019 12:01:05 -0500 Subject: [PATCH 19/26] Add Dynamic Progamming/Nth Factorial (#18) --- Dynamic Programming/Nth Factorial/README.md | 9 +++++++ Dynamic Programming/Nth Factorial/code.js | 27 +++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 Dynamic Programming/Nth Factorial/README.md create mode 100644 Dynamic Programming/Nth Factorial/code.js diff --git a/Dynamic Programming/Nth Factorial/README.md b/Dynamic Programming/Nth Factorial/README.md new file mode 100644 index 00000000..eb8986b7 --- /dev/null +++ b/Dynamic Programming/Nth Factorial/README.md @@ -0,0 +1,9 @@ +# Nth Factorial +Finding the nth Factorial using dynamic programming. + +## Complexity +* **Time**: ![](https://latex.codecogs.com/svg.latex?O(n)) +* **Space**: ![](https://latex.codecogs.com/svg.latex?O(n)) + +## References +* [TutorialsPoint](https://www.tutorialspoint.com/cplusplus-program-to-find-factorial-of-a-number-using-dynamic-programming) \ No newline at end of file diff --git a/Dynamic Programming/Nth Factorial/code.js b/Dynamic Programming/Nth Factorial/code.js new file mode 100644 index 00000000..36536239 --- /dev/null +++ b/Dynamic Programming/Nth Factorial/code.js @@ -0,0 +1,27 @@ +// import visualization libraries { +const { Tracer, Array1DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } + +// define tracer variables { +const tracer = new Array1DTracer('Sequence'); +Layout.setRoot(new VerticalLayout([tracer])); +const index = 15; +const D = [1]; +for (let i = 1; i < index; i++) { + D.push(0); +} +tracer.set(D); +Tracer.delay(); +// } + +for (let i = 1; i < index; i++) { + D[i] = D[i - 1] * i; + // visualize { + tracer.select(i - 1); + Tracer.delay(); + tracer.patch(i, D[i]); + Tracer.delay(); + tracer.depatch(i); + tracer.deselect(i - 1); + // } +} From 1f652516bebc4854cf2b40980fc263c3b0ac6c1c Mon Sep 17 00:00:00 2001 From: frankymacster Date: Thu, 19 Dec 2019 12:05:17 -0500 Subject: [PATCH 20/26] Add Simple Recursion/Nth Factorial (#19) --- Simple Recursive/Nth Factorial/README.md | 9 ++++++ Simple Recursive/Nth Factorial/code.js | 41 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 Simple Recursive/Nth Factorial/README.md create mode 100644 Simple Recursive/Nth Factorial/code.js diff --git a/Simple Recursive/Nth Factorial/README.md b/Simple Recursive/Nth Factorial/README.md new file mode 100644 index 00000000..12672dd7 --- /dev/null +++ b/Simple Recursive/Nth Factorial/README.md @@ -0,0 +1,9 @@ +# nth Factorial +Finding nth Factorial using recursion. + +## Complexity +* **Time**: ![](https://latex.codecogs.com/svg.latex?O(2ⁿ)) +* **Space**: ![](https://latex.codecogs.com/svg.latex?O(2ⁿ)) + +## References +* [codeburst.io](https://codeburst.io/learn-and-understand-recursion-in-javascript-b588218e87ea) \ No newline at end of file diff --git a/Simple Recursive/Nth Factorial/code.js b/Simple Recursive/Nth Factorial/code.js new file mode 100644 index 00000000..46089fe1 --- /dev/null +++ b/Simple Recursive/Nth Factorial/code.js @@ -0,0 +1,41 @@ +// import visualization libraries { +const { Tracer, Array1DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } + +// define tracer variables { +var tracer = new Array1DTracer('Sequence'); +Layout.setRoot(new VerticalLayout([tracer])); +var index = 15; +var D = [1]; +for (var i = 1; i < index; i++) { + D.push(0); +} +tracer.set(D); +Tracer.delay(); +// } + +function fact(num) { + if (num < 0) { + return; + } + + if (num === 0) { + return 1; + } + + var res = num * fact(num - 1); + + D[num - 1] = res; + + // visualize { + tracer.select(num - 1); + Tracer.delay(); + tracer.patch(num - 1, D[num - 1]); + Tracer.delay(); + tracer.depatch(num - 1); + tracer.deselect(num - 1); + // } + + return res; +} +fact(index); \ No newline at end of file From 8bd066fa4cb2879c4d5de04b734d371e3237782f Mon Sep 17 00:00:00 2001 From: L Xiaojian <810190163@qq.com> Date: Wed, 25 Dec 2019 00:27:19 +0800 Subject: [PATCH 21/26] Add C++ implementation in Brute Force/Bubble Sort 1. Decrease-and-conquer 2. Early termination --- Brute Force/Bubble Sort/main.cpp | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Brute Force/Bubble Sort/main.cpp diff --git a/Brute Force/Bubble Sort/main.cpp b/Brute Force/Bubble Sort/main.cpp new file mode 100644 index 00000000..e106a456 --- /dev/null +++ b/Brute Force/Bubble Sort/main.cpp @@ -0,0 +1,55 @@ +#include "algorithm-visualizer.h" + +#define N 15 +#define MIN 1 +#define MAX 20 + +void BubbleSort(int start, int end, int array[]); + +ChartTracer chartTracer("Chart"); + +int main() { + int array[N]; + Randomize::Array1D(N, *(new Randomize::Integer(MIN, MAX))).fill(&array[0]); + chartTracer.set(array); + Layout::setRoot(VerticalLayout({ chartTracer })); + + BubbleSort(0, N - 1, array); + + return 0; +} + +void BubbleSort(int start, int end, int array[]) +{ + chartTracer.select(end); + + int newEnd = start; + for(int i = start; i < end; ++i) + { + chartTracer.select(i); + chartTracer.select(i + 1); + Tracer::delay(); + if(array[i] > array[i + 1]) + { + std::swap(array[i], array[i + 1]); + chartTracer.patch(i, array[i]); + chartTracer.patch(i + 1, array[i + 1]); + Tracer::delay(); + chartTracer.depatch(i); + chartTracer.depatch(i + 1); + newEnd = i; + } + + chartTracer.deselect(i); + chartTracer.deselect(i + 1); + } + + if(newEnd == start) + { + return; + } + else + { + BubbleSort(start, newEnd, array); + } +} From 6a80b21085f208b1f3be2abcbb2e03d9e1298046 Mon Sep 17 00:00:00 2001 From: frankymacster Date: Tue, 24 Dec 2019 11:29:24 -0500 Subject: [PATCH 22/26] Add Cycle Detection (#22) --- Simple Recursive/Cycle Detection/README.md | 5 + Simple Recursive/Cycle Detection/code.js | 136 +++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 Simple Recursive/Cycle Detection/README.md create mode 100644 Simple Recursive/Cycle Detection/code.js diff --git a/Simple Recursive/Cycle Detection/README.md b/Simple Recursive/Cycle Detection/README.md new file mode 100644 index 00000000..e8c526cf --- /dev/null +++ b/Simple Recursive/Cycle Detection/README.md @@ -0,0 +1,5 @@ +# Cycle Detection +"Floyd's cycle-finding algorithm is a pointer algorithm that uses only two pointers, which move through the sequence at different speeds" + +## References +* [Wikipedia](https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_Tortoise_and_Hare) \ No newline at end of file diff --git a/Simple Recursive/Cycle Detection/code.js b/Simple Recursive/Cycle Detection/code.js new file mode 100644 index 00000000..32ca9f04 --- /dev/null +++ b/Simple Recursive/Cycle Detection/code.js @@ -0,0 +1,136 @@ +// import visualization libraries { +const { Array2DTracer, Layout, LogTracer, GraphTracer, Tracer, VerticalLayout } = require('algorithm-visualizer'); +// } + + +// define tracer variables { +function ListNode(val) { + this.val = val + this.next = null +} + +const node0 = new ListNode(0) +const node1 = new ListNode(1) +const node2 = new ListNode(2) +const node3 = new ListNode(3) +const node4 = new ListNode(4) +const node5 = new ListNode(5) +const node6 = new ListNode(6) + +const list = node0 +list.next = node1 +list.next.next = node2 +list.next.next.next = node3 +list.next.next.next.next = node4 +list.next.next.next.next.next = node5 +list.next.next.next.next.next.next = node6 +list.next.next.next.next.next.next.next = node2 + +const graphTracer = new GraphTracer("Linked List").directed() +const logTracer = new LogTracer("Console") +Layout.setRoot(new VerticalLayout([graphTracer, logTracer])) + +graphTracer.addNode(node0.val) +graphTracer.addNode(node1.val) +graphTracer.addNode(node2.val) +graphTracer.addNode(node3.val) +graphTracer.addNode(node4.val) +graphTracer.addNode(node5.val) +graphTracer.addNode(node6.val) +graphTracer.addEdge(node0.val, node1.val) +graphTracer.addEdge(node1.val, node2.val) +graphTracer.addEdge(node2.val, node3.val) +graphTracer.addEdge(node3.val, node4.val) +graphTracer.addEdge(node4.val, node5.val) +graphTracer.addEdge(node5.val, node6.val) +graphTracer.addEdge(node6.val, node2.val) +Tracer.delay() +// } + +var listHasCycle = function(head) { + // visualize { + graphTracer.select(head.val) + graphTracer.visit(head.val) + Tracer.delay() + graphTracer.deselect(head.val) + graphTracer.leave(head.val) + // } + + // 1. is there a cycle? + let slow = head.next + let fast = head.next.next + // visualize { + graphTracer.select(slow.val) + graphTracer.visit(fast.val) + Tracer.delay() + graphTracer.deselect(slow.val) + graphTracer.leave(fast.val) + // } + while (slow !== fast) { + slow = slow.next + fast = fast.next.next + // visualize { + graphTracer.select(slow.val) + graphTracer.visit(fast.val) + Tracer.delay() + graphTracer.deselect(slow.val) + graphTracer.leave(fast.val) + // } + } + + // 2. where does the cycle start? + let cycleStartPosition = 0 + slow = head + // visualize { + graphTracer.select(slow.val) + graphTracer.visit(fast.val) + Tracer.delay() + graphTracer.deselect(slow.val) + graphTracer.leave(fast.val) + // } + while (slow !== fast) { + slow = slow.next + fast = fast.next + cycleStartPosition += 1 + // visualize { + graphTracer.select(slow.val) + graphTracer.visit(fast.val) + Tracer.delay() + graphTracer.deselect(slow.val) + graphTracer.leave(fast.val) + // } + } + + // 3. what is the length of the cycle? + let cycleLength = 1 + fast = slow.next + // visualize { + graphTracer.select(slow.val) + graphTracer.visit(fast.val) + Tracer.delay() + graphTracer.deselect(slow.val) + graphTracer.leave(fast.val) + // } + while (slow !== fast) { + fast = fast.next + cycleLength += 1 + // visualize { + graphTracer.select(slow.val) + graphTracer.visit(fast.val) + Tracer.delay() + graphTracer.deselect(slow.val) + graphTracer.leave(fast.val) + // } + } + + return { + cycleLength, + cycleStartPosition, + } +} +// log { +const res = listHasCycle(list) +logTracer.print(`cycle start position: ${res.cycleStartPosition}`) +logTracer.print("\n") +logTracer.print(`cycle length: ${res.cycleLength}`) +// } \ No newline at end of file From 2881b3f18dc83c301eb88ee40d4e86bf71ffdd45 Mon Sep 17 00:00:00 2001 From: Ethienne Graveline Date: Fri, 22 May 2020 20:06:17 -0300 Subject: [PATCH 23/26] Integer partition (#24) * Fixed error in Integer Partition returns the wrong total for some values of n e.g. when n is 6 returns 14 instead of 11 This more closely resembles the code from referenced in the README: https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition * added some simple comments * fixed error in Integer Partition on some values it would print wrong partitions e.g. when n is 6 [3,3,1] is printed but is not a valid output * fixed a typo Co-authored-by: Eti --- Dynamic Programming/Integer Partition/code.js | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/Dynamic Programming/Integer Partition/code.js b/Dynamic Programming/Integer Partition/code.js index 3618098c..da4d0380 100644 --- a/Dynamic Programming/Integer Partition/code.js +++ b/Dynamic Programming/Integer Partition/code.js @@ -8,48 +8,61 @@ const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); const integer = Randomize.Integer({ min: 5, max: 14 }); const D = []; -const A = []; +const A = ""; for (let i = 0; i <= integer; i++) { D.push([]); - D[0][i] = 1; - D[i][1] = 1; - for (let j = 0; j <= integer; j++) D[i][j] = 0; + D[i][0] = 1 + for (let j = 1; j <= integer; j++) D[i][j] = 0; } tracer.set(D); Tracer.delay(); // } function partition(A, n, p) { - // logger { - if (n === 0) logger.println(`[${A.join(', ')}]`); - // } - else { - let end = n; - if (p !== 0 && A[p - 1] < n) end = A[p - 1]; - for (let i = end; i > 0; i--) { - A[p] = i; - partition(A, n - i, p + 1); + // logger { + if (p == 0) logger.println(`[${A.split('').join(', ')}]`); + // } + else { + if (n > 1) partition(A, n - 1, p); + if (n <= p) partition(n + A, n, p - n); } - } } function integerPartition(n) { - // Calculate number of partitions for all numbers from 1 to n - for (let i = 2; i <= n; i++) { - // We are allowed to use numbers from 2 to i - for (let j = 1; j <= i; j++) { - // Number of partitions without j number + number of partitions with max j - // visualize { - tracer.select(i, j); - Tracer.delay(); - // } - D[i][j] = D[i][j - 1] + D[i - j][Math.max(j, i - j)]; - // visualize { - tracer.patch(i, j, D[i][j]); - Tracer.delay(); - tracer.depatch(i, j); - tracer.deselect(i, j); - // } + + // cycle through each cell of matrix + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= n; j++) { + if (i > j) { + // visualize { + tracer.select(i, j); + Tracer.delay(); + // } + // set cell to cell above it + D[i][j] = D[i - 1][j]; + // visualize { + tracer.patch(i, j, D[i][j]); + Tracer.delay(); + tracer.depatch(i, j); + tracer.deselect(i, j); + // } + } + else { + // visualize { + tracer.select(i, j); + Tracer.delay(); + // } + // grab above cell and add it to previous cell + const above = D[i - 1][j]; + const left = D[i][j - i]; + D[i][j] = above + left; + // visualize { + tracer.patch(i, j, D[i][j]); + Tracer.delay(); + tracer.depatch(i, j); + tracer.deselect(i, j); + // } + } } } return D[n][n]; @@ -58,7 +71,7 @@ function integerPartition(n) { // logger { logger.println(`Partitioning: ${integer}`); // } -partition(A, integer, 0); +partition(A, integer, integer); const part = integerPartition(integer); // logger { logger.println(part); From cbb3b2de24d2b922983c80058f3c08b6321d3cab Mon Sep 17 00:00:00 2001 From: Jinseo Park Date: Thu, 28 Jan 2021 02:24:04 -0500 Subject: [PATCH 24/26] Update algorithm-visualizer version --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index da6ea512..6f6db3b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,13 @@ { - "name": "algorithms-validator", + "name": "algorithms", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "algorithm-visualizer": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/algorithm-visualizer/-/algorithm-visualizer-2.3.5.tgz", - "integrity": "sha512-c1jJmJ1ba4qfDrWfW6TMWXs1mvj6uyUva2uhbNwg655r8/VXauvbXrYkF0E1j7JBTA2POep4Kl4AD1T/UKSuRA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/algorithm-visualizer/-/algorithm-visualizer-2.3.8.tgz", + "integrity": "sha512-0oNDbQRpf2P8F3FgyrehBde+c23R/wYbrqb2jSChDof2dZT/U/iQQ0WHE10MEmD7zucNHxmt60RNZDGu7CQ2BA==", "requires": { "axios": "^0.18.0", "opn": "^5.4.0" @@ -124,9 +124,9 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" }, "is-wsl": { "version": "1.1.0", From 713869809f514f73631b157de3718545053bf958 Mon Sep 17 00:00:00 2001 From: Jeff Tian Date: Thu, 28 Jan 2021 15:24:28 +0800 Subject: [PATCH 25/26] feat: Add k-means clustering (#27) --- Uncategorized/K-Means Clustering/README.md | 13 ++ Uncategorized/K-Means Clustering/code.js | 172 +++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 Uncategorized/K-Means Clustering/README.md create mode 100644 Uncategorized/K-Means Clustering/code.js diff --git a/Uncategorized/K-Means Clustering/README.md b/Uncategorized/K-Means Clustering/README.md new file mode 100644 index 00000000..6e2a759c --- /dev/null +++ b/Uncategorized/K-Means Clustering/README.md @@ -0,0 +1,13 @@ +# K-Means Clustering +K-means clustering is a method to partition _n_ observations into _k_ clusters in which each observation belongs to +the cluster with the nearest mean (cluster centers or cluster centroid). + +Given a set of observations, where each observation is a d-dimensional real vector, _k-means_ clustering aims to +partition the _n_ observations into _k(≤ n)_ sets so as to minimize the within-cluster sum of squares (i.e. variance). + +## Complexity +* **Time**: ![$O(n^{2k+1})$](https://latex.codecogs.com/svg.latex?O(n^{2k+1})) for 2-dimensional real vector + +## References +* [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering) +* [Inspired by kmeans.js.org](https://kmeans.js.org/) diff --git a/Uncategorized/K-Means Clustering/code.js b/Uncategorized/K-Means Clustering/code.js new file mode 100644 index 00000000..a82deedb --- /dev/null +++ b/Uncategorized/K-Means Clustering/code.js @@ -0,0 +1,172 @@ +// import visualization libraries { +const { + Array2DTracer, + Layout, + LogTracer, + Tracer, + VerticalLayout, + ScatterTracer, + Randomize, +} = require('algorithm-visualizer') +// } + +// define helper functions { +const shuffle = a => { + const array = a.slice(0) + const copy = [] + let n = array.length + + while (n) { + let i = Math.floor(Math.random() * n--) + copy.push(array.splice(i, 1)[0]) + } + + return copy +} + +const sum = (x, y) => x + y +const chooseRandomCenters = (data, k) => shuffle(data).slice(0, k) +const pointify = ([x, y]) => `(${x}, ${y})` +const arrayify = a => a.map(pointify) +const stringify = a => arrayify(a).join(', ') +const distance = ([x1, y1], [x2, y2]) => sum(Math.pow(x1 - x2, 2), + Math.pow(y1 - y2, 2)) +const col = (a, i) => a.map(p => p[i]) +const mean = a => a.reduce(sum, 0) / a.length +const centerOfCluster = cluster => [ + mean(col(cluster, 0)), + mean(col(cluster, 1)), +] +const reCalculateCenters = clusters => clusters.map(centerOfCluster) +const areCentersEqual = (c1, c2) => !!c1 && !!c2 && !(c1 < c2 || c2 < c1) + +function cluster(data, centers) { + const clusters = centers.map(() => []) + + for (let i = 0; i < data.length; i++) { + const point = data[i] + let minDistance = Infinity + let minDistanceIndex = -1 + + for (let j = 0; j < centers.length; j++) { + const d = distance(point, centers[j]) + + if (d < minDistance) { + minDistance = d + minDistanceIndex = j + } + } + + if (!clusters[minDistanceIndex] instanceof Array) { + clusters[minDistanceIndex] = [] + } + + clusters[minDistanceIndex].push(point) + } + + return clusters +} + +// } + +// define tracer variables { +const array2dTracer = new Array2DTracer('Grid') +const logTracer = new LogTracer('Console') +const scatterTracer = new ScatterTracer('Scatter') +// } + +// define input variables +const unClusteredData = Randomize.Array2D( + { N: Randomize.Integer({ min: 10, max: 25 }) }) +const k = Randomize.Integer( + { min: 2, max: Math.floor(unClusteredData.length / 5) }) + +const recenterAndCluster = (originalClusters) => { + const centers = reCalculateCenters(originalClusters) + const clusters = cluster(unClusteredData, centers) + return { centers, clusters } +} + +const improve = (loops, clusters, centers) => { + const allowImprove = () => loops < 1000 + + if (!allowImprove()) { + return { clusters, centers } + } + + loops++ + + const ret = recenterAndCluster(clusters) + + // trace { + array2dTracer.set(clusters.map(c => c.map(pointify))) + scatterTracer.set([unClusteredData, ...ret.clusters, ret.centers]) + + logTracer.println('') + logTracer.println(`Iteration #${loops} Result: `) + logTracer.println(`\tClusters:`) + logTracer.println( + `\t\t${ret.clusters.map(c => stringify(c)).join(`\n\t\t`)}`) + logTracer.println(`\tCenters:`) + logTracer.println(`\t\t${stringify(ret.centers)}`) + logTracer.println('') + + Tracer.delay() + // } + + if (!allowImprove() || areCentersEqual(centers, ret.centers)) { + return ret + } + + return improve(loops, ret.clusters, ret.centers) +} + +(function main() { + // visualize { + Layout.setRoot(new VerticalLayout([scatterTracer, array2dTracer, logTracer])) + + logTracer.println(`Un-clustered data = ${stringify(unClusteredData)}`) + array2dTracer.set([unClusteredData.map(pointify)]) + scatterTracer.set([unClusteredData]) + + Tracer.delay() + // } + + // Start with random centers + const centers = chooseRandomCenters(unClusteredData, k) + + // trace { + logTracer.println( + `Initial random selected centers = ${stringify(centers)}`) + scatterTracer.set([unClusteredData, ...[[], []], centers]) + + Tracer.delay() + // } + + // Cluster to the random centers + const clusters = cluster(unClusteredData, centers) + + // trace { + logTracer.println( + `Initial clusters = \n\t${clusters.map(stringify).join('\n\t')}`) + array2dTracer.set(clusters.map(c => c.map(pointify))) + scatterTracer.set([unClusteredData, ...clusters, centers]) + + Tracer.delay() + // } + + // start iterations here + const ret = improve(0, clusters, centers) + + // trace { + Tracer.delay() + + logTracer.println( + `Final clustered data = \n\t${ret.clusters.map(stringify) + .join('\n\t')}`) + logTracer.println(`Best centers = ${stringify(ret.centers)}`) + array2dTracer.set(ret.clusters.map(c => c.map(pointify))) + scatterTracer.set([unClusteredData, ...ret.clusters, ret.centers]) + Tracer.delay() + // } +})() From fe3adcf890da652e5cda842d7f90b50fa7242e3a Mon Sep 17 00:00:00 2001 From: William E Bodell III Date: Sun, 21 Mar 2021 17:48:14 -0500 Subject: [PATCH 26/26] Fix counts array visualization in Counting Sort (#28) * Fix counts array visualization in Counting Sort Final step did not correctly visualize decrementing the value in the counts array. It was decrementing the value but not updating the visualization. * Add countsTracer.depatch My previously committed code left the boxes in the counts array colored red, so I realized I had forgotten to add a depatch after the patch that I added at line 66 --- Divide and Conquer/Counting Sort/code.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Divide and Conquer/Counting Sort/code.js b/Divide and Conquer/Counting Sort/code.js index aea80f8f..4293fade 100644 --- a/Divide and Conquer/Counting Sort/code.js +++ b/Divide and Conquer/Counting Sort/code.js @@ -58,15 +58,17 @@ const array = Randomize.Array1D({ N, value: () => Randomize.Integer({ min: 0, ma const number = array[i]; const count = counts[number]; sortedArray[count - 1] = number; + counts[number]--; // visualize { arrayTracer.select(i); countsTracer.select(number); sortedArrayTracer.patch(count - 1, sortedArray[count - 1]); + countsTracer.patch(number, counts[number]); Tracer.delay(); sortedArrayTracer.depatch(count - 1); + countsTracer.depatch(number); countsTracer.deselect(number); arrayTracer.deselect(i); // } - counts[number]--; } })(); pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy