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/Backtracking/Hamiltonean Cycles/Code.java b/Backtracking/Hamiltonean Cycles/Code.java new file mode 100644 index 00000000..ad17c28e --- /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;i3 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/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 Randomize.Integer({ min: 0, max: 50 }), sorted: true }); 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[new Randomize.Integer(0, D.length - 1).create()]; +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 4e4c753a..814e64ac 100644 --- a/Branch and Bound/Binary Search/recursive.js +++ b/Branch and Bound/Binary Search/recursive.js @@ -1,23 +1,30 @@ +// 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(); 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(); +// } 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[new Randomize.Integer(0, D.length - 1).create()]; +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 2c61b3fc..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++) { @@ -37,4 +44,7 @@ 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 29544d46..0875ad82 100644 --- a/Brute Force/Breadth-First Search/shortestPath.js +++ b/Brute Force/Breadth-First Search/shortestPath.js @@ -1,12 +1,16 @@ +// 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])); 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(); +// } 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(); + // } } } } @@ -36,16 +46,20 @@ 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 { 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 0c771d42..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,24 +15,36 @@ 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(); + // } } } } } + BFS(0); 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 0aeb0ec8..a69ae686 100644 --- a/Brute Force/Bubble Sort/code.js +++ b/Brute Force/Bubble Sort/code.js @@ -1,39 +1,59 @@ +// 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(); 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(); +// } +// 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/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); + } +} 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); + } + +} diff --git a/Brute Force/Comb Sort/code.js b/Brute Force/Comb Sort/code.js index 06072261..6d3bc2ae 100644 --- a/Brute Force/Comb Sort/code.js +++ b/Brute Force/Comb Sort/code.js @@ -1,15 +1,21 @@ +// 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(); 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(); +// } +// 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 bb41fa34..9dac822a 100644 --- a/Brute Force/Cycle Sort/code.js +++ b/Brute Force/Cycle Sort/code.js @@ -1,15 +1,21 @@ +// 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(); 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(); +// } +// 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 d7928980..07660a77 100644 --- a/Brute Force/Depth-First Search/graph.js +++ b/Brute Force/Depth-First Search/graph.js @@ -1,13 +1,17 @@ +// 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(); 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(); +// } 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 0b9da4e9..646b865c 100644 --- a/Brute Force/Depth-First Search/shortestPath.js +++ b/Brute Force/Depth-First Search/shortestPath.js @@ -1,28 +1,38 @@ +// 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])); 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(); +// } 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,23 +41,29 @@ 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 = 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; +// 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..27dbb865 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 53a25d19..b57b1f0b 100644 --- a/Brute Force/Depth-First Search/weightedGraph.js +++ b/Brute Force/Depth-First Search/weightedGraph.js @@ -1,18 +1,24 @@ +// 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])); 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(); +// } 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 8ffed673..d0abb120 100644 --- a/Brute Force/Heapsort/code.js +++ b/Brute Force/Heapsort/code.js @@ -1,22 +1,28 @@ +// 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(); 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 { logger.println(`Original array = [${D.join(', ')}]`); +// } function heapSort(array, size) { let i; 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); } @@ -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/Brute Force/Insertion Sort/code.js b/Brute Force/Insertion Sort/code.js index a655e780..7b3db3d0 100644 --- a/Brute Force/Insertion Sort/code.js +++ b/Brute Force/Insertion Sort/code.js @@ -1,31 +1,45 @@ +// 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(); 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(); +// } +// 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 c694c08d..8332c37c 100644 --- a/Brute Force/PageRank/code.js +++ b/Brute Force/PageRank/code.js @@ -1,10 +1,13 @@ +// 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); } -const G = new Randomize.Graph(5, .4).create(); +// define tracer variables { +const G = Randomize.Graph({ N: 5, ratio: .4 }); let ranks; const outgoingEdgeCounts = filledArray(G.length, 0); let incomingNodes; @@ -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 d40a6a9b..4e066872 100644 --- a/Brute Force/Pancake Sort/code.js +++ b/Brute Force/Pancake Sort/code.js @@ -1,45 +1,73 @@ +// 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(); 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 { 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] }); + 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 26144ccc..41af8a11 100644 --- a/Brute Force/Selection Sort/code.js +++ b/Brute Force/Selection Sort/code.js @@ -1,41 +1,63 @@ +// 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(); 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(); +// } +// 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 cdaeccaa..333ad2ce 100644 --- a/Brute Force/Shellsort/code.js +++ b/Brute Force/Shellsort/code.js @@ -1,36 +1,53 @@ +// 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(); 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(); +// } +// 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/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/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..4293fade 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 @@ -58,15 +58,17 @@ const array = new Randomize.Array1D(N, new Randomize.Integer(0, 9)).create(); 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]--; } })(); diff --git a/Divide and Conquer/Merge Sort/bottomUp.js b/Divide and Conquer/Merge Sort/bottomUp.js index 18a9c727..e3200fed 100644 --- a/Divide and Conquer/Merge Sort/bottomUp.js +++ b/Divide and Conquer/Merge Sort/bottomUp.js @@ -1,17 +1,23 @@ +// 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])); 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); 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 177b7efc..9ad9b208 100644 --- a/Divide and Conquer/Merge Sort/topDown.js +++ b/Divide and Conquer/Merge Sort/topDown.js @@ -1,15 +1,21 @@ +// 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(); 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(); +// } +// 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 b3d68876..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 = new Randomize.Array1D(7).create(); +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 59f5fd21..4eb5373b 100644 --- a/Divide and Conquer/Quicksort/code.js +++ b/Divide and Conquer/Quicksort/code.js @@ -1,15 +1,21 @@ +// 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(); 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(); +// } +// 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 4b2af6fd..1d0d3ea6 100644 --- a/Divide and Conquer/Radix Sort/leastSignificantDigit.js +++ b/Divide and Conquer/Radix Sort/leastSignificantDigit.js @@ -1,9 +1,12 @@ +// 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])); -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], @@ -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 ef9e16ab..69cae5bb 100644 --- a/Dynamic Programming/Bellman-Ford's Shortest Path/code.js +++ b/Dynamic Programming/Bellman-Ford's Shortest Path/code.js @@ -1,12 +1,16 @@ +// 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])); 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(); +// } 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,19 +72,23 @@ 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]; } -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,16 +99,20 @@ let minWeight; */ do { - dest = new Randomize.Integer(0, G.length - 1).create(); + dest = Randomize.Integer({ min: 0, max: G.length - 1 }); } 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 0b01b6ad..e526c293 100644 --- a/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js +++ b/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js @@ -1,12 +1,16 @@ +// 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])); 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(); +// } 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 394753ef..da4d0380 100644 --- a/Dynamic Programming/Integer Partition/code.js +++ b/Dynamic Programming/Integer Partition/code.js @@ -1,51 +1,78 @@ +// 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])); -const integer = new Randomize.Integer(5, 14).create(); +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) { - 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 - tracer.select(i, j); - Tracer.delay(); - D[i][j] = D[i][j - 1] + D[i - j][Math.max(j, i - j)]; - 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]; } +// logger { logger.println(`Partitioning: ${integer}`); -partition(A, integer, 0); +// } +partition(A, integer, integer); 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..21855d03 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,15 +15,17 @@ 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(); +// } for (let i = 0; i <= N; i++) { for (let j = 0; j <= W; j++) { @@ -31,17 +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 - dataViewer1.select(i - 1); - Tracer.delay(); - dataViewer2.select(i - 1); + // visualize { + 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]; /* @@ -50,25 +57,36 @@ 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(); + // } } - - tracer.deselect(i - 1, j); + // visualize { + // 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]; + // 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/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); 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 1d80fc81..1cc46e40 100644 --- a/Dynamic Programming/Longest Increasing Subsequence/code.js +++ b/Dynamic Programming/Longest Increasing Subsequence/code.js @@ -1,41 +1,59 @@ +// 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 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(); +// } // 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 db55f763..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) { @@ -30,56 +33,82 @@ 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); @@ -88,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 8ff4f3e6..b95e518e 100644 --- a/Dynamic Programming/Maximum Sum Path/code.js +++ b/Dynamic Programming/Maximum Sum Path/code.js @@ -1,6 +1,9 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const D = new Randomize.Array2D(5, 5, new Randomize.Integer(1, 5)).create(); +// 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'); const logger = new LogTracer(); @@ -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/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); + // } +} 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 01de463e..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 = 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(); +// } 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 a2e1b34b..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,76 +33,103 @@ 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(); + Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); + // } right++; } + // visualize { if (right < N) { 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); } + // } 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(); + Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); + // } right++; } + // visualize { if (right < N) { 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); } + // } 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 230d79de..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 = new Randomize.Graph(5, 1).directed(false).weighted().create(); 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,37 +42,47 @@ 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 = 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 { 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 51ab1360..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])); @@ -10,9 +13,10 @@ 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(); +// } 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 e3479538..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])); @@ -11,9 +14,10 @@ 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(); +// } 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 06886f76..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(); + 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); 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(); + Tracer.delay(); + // } a.stable = b; b.stable = a; + // visualize { tracerA.select(_aKeys.indexOf(a.key)); -Tracer.delay(); + Tracer.delay(); tracerB.select(_bKeys.indexOf(b.key)); -Tracer.delay(); + Tracer.delay(); + // } } } } diff --git a/README.md b/README.md index 9fe9aec1..de35242c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ -# Algorithms +# Algorithms [![Travis (.com)](https://img.shields.io/travis/com/algorithm-visualizer/algorithms.svg?style=flat-square)](https://travis-ci.com/algorithm-visualizer/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 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/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 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/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 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 adcd087f..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(); + 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(); + 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/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() + // } +})() 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; } 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 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..6f6db3b3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,260 @@ +{ + "name": "algorithms", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "algorithm-visualizer": { + "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" + } + }, + "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.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", + "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" + } +} 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