diff --git a/Backtracking/Knight's Tour Problem/code.js b/Backtracking/Knight's Tour Problem/code.js index ceeb7f62..e334bc8f 100644 --- a/Backtracking/Knight's Tour Problem/code.js +++ b/Backtracking/Knight's Tour Problem/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } /* For N>3 the time taken by this algorithm is sufficiently high @@ -26,6 +28,7 @@ const Y = [1, 2, 2, 1, -1, -2, -2, -1]; const pos = new Array(2); pos[0] = pos[1] = -1; +// define tracer variables { const boardTracer = new Array2DTracer('Board'); const posTracer = new Array1DTracer('Knight Position'); const logTracer = new LogTracer('Console'); @@ -33,6 +36,7 @@ boardTracer.set(board); posTracer.set(pos); Layout.setRoot(new VerticalLayout([boardTracer, posTracer, logTracer])); Tracer.delay(); +// } function knightTour(x, y, moveNum) { if (moveNum === N * N) { @@ -43,12 +47,14 @@ function knightTour(x, y, moveNum) { const nextX = x + X[i]; const nextY = y + Y[i]; + // visualize { posTracer.patch(0, nextX); Tracer.delay(); posTracer.patch(1, nextY); Tracer.delay(); posTracer.depatch(0); posTracer.depatch(1); + // } /* Check if knight is still in the board Check that knight does not visit an already visited square @@ -56,24 +62,33 @@ function knightTour(x, y, moveNum) { if (nextX >= 0 && nextX < N && nextY >= 0 && nextY < N && board[nextX][nextY] === -1) { board[nextX][nextY] = moveNum; + // visualize { logTracer.println(`Move to ${nextX},${nextY}`); boardTracer.patch(nextX, nextY, moveNum); Tracer.delay(); boardTracer.depatch(nextX, nextY); boardTracer.select(nextX, nextY); + // } const nextMoveNum = moveNum + 1; if (knightTour(nextX, nextY, nextMoveNum) === true) { return true; } + + // logger { logTracer.println(`No place to move from ${nextX},${nextY}: Backtrack`); + // } board[nextX][nextY] = -1; // backtrack + // visualize { boardTracer.patch(nextX, nextY, -1); Tracer.delay(); boardTracer.depatch(nextX, nextY); boardTracer.deselect(nextX, nextY); + // } } else { + // logger { logTracer.println(`${nextX},${nextY} is not a valid move`); + // } } } return false; @@ -83,6 +98,7 @@ board[0][0] = 0; // start from this position pos[0] = 0; pos[0] = 0; +// visualize { boardTracer.patch(0, 0, 0); Tracer.delay(); posTracer.patch(0, 0); @@ -93,9 +109,12 @@ boardTracer.depatch(0, 0); boardTracer.depatch(0, 0); posTracer.depatch(0); posTracer.depatch(1); +// } +// logger { if (knightTour(0, 0, 1) === false) { logTracer.println('Solution does not exist'); } else { logTracer.println('Solution found'); } +// } diff --git a/Backtracking/N-Queens Problem/code.js b/Backtracking/N-Queens Problem/code.js index 7812dd40..5f2e5b90 100644 --- a/Backtracking/N-Queens Problem/code.js +++ b/Backtracking/N-Queens Problem/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 4; // just change the value of N and the visuals will reflect the configuration! const board = (function createArray(N) { @@ -16,6 +18,7 @@ const queens = (function qSetup(N) { return result; }(N)); +// define tracer variables { const boardTracer = new Array2DTracer('Board'); const queenTracer = new Array2DTracer('Queen Positions'); const logger = new LogTracer('Progress'); @@ -25,6 +28,7 @@ boardTracer.set(board); queenTracer.set(queens); logger.println(`N Queens: ${N}X${N}matrix, ${N} queens`); Tracer.delay(); +// } function validState(row, col, currentQueen) { for (let q = 0; q < currentQueen; q++) { @@ -37,24 +41,31 @@ function validState(row, col, currentQueen) { } function nQ(currentQueen, currentCol) { + // logger { logger.println(`Starting new iteration of nQueens () with currentQueen = ${currentQueen} & currentCol = ${currentCol}`); logger.println('------------------------------------------------------------------'); + // } if (currentQueen >= N) { + // logger { logger.println('The recursion has BOTTOMED OUT. All queens have been placed successfully'); + // } return true; } let found = false; let row = 0; while ((row < N) && (!found)) { + // visualize { boardTracer.select(row, currentCol); Tracer.delay(); logger.println(`Trying queen ${currentQueen} at row ${row} & col ${currentCol}`); - + // } + if (validState(row, currentCol, currentQueen)) { queens[currentQueen][0] = row; queens[currentQueen][1] = currentCol; + // visualize { queenTracer.patch(currentQueen, 0, row); Tracer.delay(); queenTracer.patch(currentQueen, 1, currentCol); @@ -63,14 +74,17 @@ function nQ(currentQueen, currentCol) { Tracer.delay(); queenTracer.depatch(currentQueen, 1); Tracer.delay(); - + // } + found = nQ(currentQueen + 1, currentCol + 1); } if (!found) { + // visualize { boardTracer.deselect(row, currentCol); Tracer.delay(); logger.println(`row ${row} & col ${currentCol} didn't work out. Going down`); + // } } row++; } @@ -78,6 +92,10 @@ function nQ(currentQueen, currentCol) { return found; } +// logger { logger.println('Starting execution'); +// } nQ(0, 0); +// logger { logger.println('DONE'); +// } diff --git a/Branch and Bound/Binary Search Tree/insertion.js b/Branch and Bound/Binary Search Tree/insertion.js index a2656c45..f327b301 100644 --- a/Branch and Bound/Binary Search Tree/insertion.js +++ b/Branch and Bound/Binary Search Tree/insertion.js @@ -1,8 +1,12 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const T = {}; const elements = [5, 8, 10, 3, 1, 6, 9, 7, 2, 0, 4]; // item to be inserted + +// define tracer variables { const graphTracer = new GraphTracer(' BST - Elements marked red indicates the current status of tree '); const elemTracer = new Array1DTracer(' Elements '); const logger = new LogTracer(' Log '); @@ -10,10 +14,13 @@ Layout.setRoot(new VerticalLayout([graphTracer, elemTracer, logger])); elemTracer.set(elements); graphTracer.log(logger); Tracer.delay(); +// } function bstInsert(root, element, parent) { // root = current node , parent = previous node + // visualize { graphTracer.visit(root, parent); Tracer.delay(); + // } const treeNode = T[root]; let propName = ''; if (element < root) { @@ -25,30 +32,40 @@ function bstInsert(root, element, parent) { // root = current node , parent = pr if (!(propName in treeNode)) { // insert as left child of root treeNode[propName] = element; T[element] = {}; + // visualize { graphTracer.addNode(element); graphTracer.addEdge(root, element); graphTracer.select(element, root); Tracer.delay(); graphTracer.deselect(element, root); logger.println(`${element} Inserted`); + // } } else { bstInsert(treeNode[propName], element, root); } } + // visualize { graphTracer.leave(root, parent); Tracer.delay(); + // } } const Root = elements[0]; // take first element as root T[Root] = {}; +// visualize { graphTracer.addNode(Root); graphTracer.layoutTree(Root, true); logger.println(`${Root} Inserted as root of tree `); +// } for (let i = 1; i < elements.length; i++) { + // visualize { elemTracer.select(i); Tracer.delay(); + // } bstInsert(Root, elements[i]); // insert ith element + // visualize { elemTracer.deselect(i); Tracer.delay(); + // } } diff --git a/Branch and Bound/Binary Search Tree/search.js b/Branch and Bound/Binary Search Tree/search.js index f45f5f8a..0d9fdf0c 100644 --- a/Branch and Bound/Binary Search Tree/search.js +++ b/Branch and Bound/Binary Search Tree/search.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -29,6 +31,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ ]; const key = Randomize.Integer({ min: 0, max: G.length - 1 }); // item to be searched +// define tracer variables { const tracer = new GraphTracer(' Binary Search Tree '); const logger = new LogTracer(' Log '); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -36,26 +39,37 @@ tracer.set(G); tracer.layoutTree(5); tracer.log(logger); Tracer.delay(); +// } function bst(item, node, parent) { // node = current node , parent = previous node + // visualize { tracer.visit(node, parent); Tracer.delay(); + // } if (item === node) { // key found + // logger { logger.println(' Match Found '); + // } } else if (item < node) { // key less than value of current node if (T[node][0] === -1) { + // logger { logger.println(' Not Found '); + // } } else { bst(item, T[node][0], node); } } else { // key greater than value of current node if (T[node][1] === -1) { + // logger { logger.println(' Not Found '); + // } } else { bst(item, T[node][1], node); } } } +// logger { logger.println(`Finding number ${key}`); +// } bst(key, 5); // node with key 5 is the root diff --git a/Branch and Bound/Binary Search/iterative.js b/Branch and Bound/Binary Search/iterative.js index 5bb2d658..3fd3e005 100644 --- a/Branch and Bound/Binary Search/iterative.js +++ b/Branch and Bound/Binary Search/iterative.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,6 +11,7 @@ const D = Randomize.Array1D({ N: 15, value: () => Randomize.Integer({ min: 0, ma tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } function BinarySearch(array, element) { // array = sorted array, element = element to be found let minIndex = 0; @@ -18,6 +22,7 @@ function BinarySearch(array, element) { // array = sorted array, element = eleme const middleIndex = Math.floor((minIndex + maxIndex) / 2); testElement = array[middleIndex]; + // visualize { tracer.select(minIndex, maxIndex); Tracer.delay(); tracer.patch(middleIndex); @@ -25,26 +30,37 @@ function BinarySearch(array, element) { // array = sorted array, element = eleme Tracer.delay(); tracer.depatch(middleIndex); tracer.deselect(minIndex, maxIndex); + // } if (testElement < element) { + // logger { logger.println('Going right.'); + // } minIndex = middleIndex + 1; } else if (testElement > element) { + // logger { logger.println('Going left.'); + // } maxIndex = middleIndex - 1; } else { + // visualize { logger.println(`${element} is found at position ${middleIndex}!`); tracer.select(middleIndex); + // } return middleIndex; } } + // logger { logger.println(`${element} is not found!`); + // } return -1; } const element = D[Randomize.Integer({ min: 0, max: D.length - 1 })]; +// logger { logger.println(`Using iterative binary search to find ${element}`); +// } BinarySearch(D, element); diff --git a/Branch and Bound/Binary Search/recursive.js b/Branch and Bound/Binary Search/recursive.js index 2a20e61d..814e64ac 100644 --- a/Branch and Bound/Binary Search/recursive.js +++ b/Branch and Bound/Binary Search/recursive.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,16 +11,20 @@ const D = Randomize.Array1D({ N: 15, value: () => Randomize.Integer({ min: 0, ma tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } function BinarySearch(array, element, minIndex, maxIndex) { // array = sorted array, element = element to be found, minIndex = low index, maxIndex = high index if (minIndex > maxIndex) { + // logger { logger.println(`${element} is not found!`); + // } return -1; } const middleIndex = Math.floor((minIndex + maxIndex) / 2); const testElement = array[middleIndex]; + // visualize { tracer.select(minIndex, maxIndex); Tracer.delay(); tracer.patch(middleIndex); @@ -25,28 +32,39 @@ function BinarySearch(array, element, minIndex, maxIndex) { // array = sorted ar Tracer.delay(); tracer.depatch(middleIndex); tracer.deselect(minIndex, maxIndex); + // } if (testElement < element) { + // logger { logger.println('Going right.'); + // } return BinarySearch(array, element, middleIndex + 1, maxIndex); } if (testElement > element) { + // logger { logger.println('Going left.'); + // } return BinarySearch(array, element, minIndex, middleIndex - 1); } if (testElement === element) { + // visualize { logger.println(`${element} is found at position ${middleIndex}!`); tracer.select(middleIndex); + // } return middleIndex; } + // logger { logger.println(`${element} is not found!`); + // } return -1; } const element = D[Randomize.Integer({ min: 0, max: D.length - 1 })]; +// logger { logger.println(`Using binary search to find ${element}`); +// } BinarySearch(D, element, 0, D.length - 1); diff --git a/Branch and Bound/Depth-Limited Search/code.js b/Branch and Bound/Depth-Limited Search/code.js index b4f2530d..21709b93 100644 --- a/Branch and Bound/Depth-Limited Search/code.js +++ b/Branch and Bound/Depth-Limited Search/code.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); -tracer.log(logger); const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], @@ -17,15 +15,24 @@ const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); +tracer.log(logger); tracer.set(G); tracer.layoutTree(0); Tracer.delay(); +// } // This is a sample DLS applications where // we try to find number of descendant of root within some depth function DLSCount(limit, node, parent) { // node = current node, parent = previous node + // visualize { tracer.visit(node, parent); Tracer.delay(); + // } let child = 0; if (limit > 0) { // cut off the search for (let i = 0; i < G[node].length; i++) { @@ -38,4 +45,6 @@ function DLSCount(limit, node, parent) { // node = current node, parent = previo return child; } +// logger { logger.println(`Number of descendant is ${DLSCount(2, 0)}`); +// } diff --git a/Branch and Bound/Topological Sort/code.js b/Branch and Bound/Topological Sort/code.js index e55b7124..9f08909b 100644 --- a/Branch and Bound/Topological Sort/code.js +++ b/Branch and Bound/Topological Sort/code.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); -tracer.log(logger); // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not. NOTE: The graph must be Directed-Acyclic const G = [ [0, 0, 0, 0, 0, 0], @@ -13,70 +11,108 @@ const G = [ [1, 0, 0, 1, 0, 0], [1, 1, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); +tracer.log(logger); tracer.set(G); Tracer.delay(); +// } const inDegrees = Array(...Array(G.length)).map(Number.prototype.valueOf, 0); // create an Array of G.length number of 0s const Q = []; let iter = 0; let i; +// logger { logger.println('Calculating in-degrees for each Node...'); +// } + for (let currNode = 0; currNode < G.length; currNode++) { for (let currNodeNeighbor = 0; currNodeNeighbor < G.length; currNodeNeighbor++) { if (G[currNode][currNodeNeighbor]) { + // visualize { logger.println(`${currNodeNeighbor} has an incoming edge from ${currNode}`); tracer.visit(currNodeNeighbor, currNode); Tracer.delay(); + // } inDegrees[currNodeNeighbor]++; + // visualize { tracer.leave(currNodeNeighbor, currNode); Tracer.delay(); + // } } } } +// logger { logger.println(`Done. In-Degrees are: [ ${String(inDegrees)} ]`); logger.println(''); logger.println('Initializing queue with all the sources (nodes with no incoming edges)'); +// } inDegrees.map((indegrees, node) => { + // visualize { tracer.visit(node); Tracer.delay(); + // } if (!indegrees) { + // logger { logger.println(`${node} is a source`); + // } Q.push(node); } + // visualize { tracer.leave(node); Tracer.delay(); + // } }); +// logger { logger.println(`Done. Initial State of Queue: [ ${String(Q)} ]`); logger.println(''); +// } // begin topological sort (kahn) while (Q.length > 0) { + // logger { logger.println(`Iteration #${iter}. Queue state: [ ${String(Q)} ]`); + // } const currNode = Q.shift(); + // visualize { tracer.visit(currNode); Tracer.delay(); + // } for (i = 0; i < G.length; i++) { if (G[currNode][i]) { + // visualize { logger.println(`${i} has an incoming edge from ${currNode}. Decrementing ${i}'s in-degree by 1.`); tracer.visit(i, currNode); Tracer.delay(); + // } inDegrees[i]--; + // visualize { tracer.leave(i, currNode); Tracer.delay(); + // } if (!inDegrees[i]) { + // logger { logger.println(`${i}'s in-degree is now 0. Enqueuing ${i}`); + // } Q.push(i); } } } + // visualize { tracer.leave(currNode); Tracer.delay(); + // } + // logger { logger.println(`In-degrees are: [${String(inDegrees)} ]`); logger.println('-------------------------------------------------------------------'); - + // } + iter++; } diff --git a/Brute Force/Binary Tree Traversal/inOrder.js b/Brute Force/Binary Tree Traversal/inOrder.js index 8f8e26b2..1970212f 100644 --- a/Brute Force/Binary Tree Traversal/inOrder.js +++ b/Brute Force/Binary Tree Traversal/inOrder.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,6 +30,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer('Traversal In-order'); const arrayTracer = new Array1DTracer('Print In-order'); const logger = new LogTracer('Log'); @@ -36,24 +39,30 @@ treeTracer.set(G); treeTracer.layoutTree(5); arrayTracer.set(new Array(T.length).fill('-')); Tracer.delay(); +// } let index = 0; function inOrder(root, parent) { if (root === -1) { + // logger { logger.println('No more nodes. Backtracking.'); Tracer.delay(); + // } return; } + // visualize { logger.println(`Reached ${root}`); treeTracer.visit(root, parent); Tracer.delay(); logger.println(` Going left from ${root}`); Tracer.delay(); + // } inOrder(T[root][0], root); + // visualize { logger.println(`Printing ${root}`); treeTracer.leave(root); arrayTracer.patch(index++, root); @@ -61,8 +70,11 @@ function inOrder(root, parent) { logger.println(` Going right from ${root}`); Tracer.delay(); + // } inOrder(T[root][1], root); } inOrder(5); // node with key 5 is the root +// logger { logger.println('Finished'); +// } diff --git a/Brute Force/Binary Tree Traversal/postOrder.js b/Brute Force/Binary Tree Traversal/postOrder.js index e34b9752..c6da428b 100644 --- a/Brute Force/Binary Tree Traversal/postOrder.js +++ b/Brute Force/Binary Tree Traversal/postOrder.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,6 +30,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer('Traversal Post-order'); const arrayTracer = new Array1DTracer('Print Post-order'); const logger = new LogTracer('Log'); @@ -36,33 +39,44 @@ treeTracer.set(G); treeTracer.layoutTree(5); arrayTracer.set(new Array(T.length).fill('-')); Tracer.delay(); +// } let index = 0; function postOrder(root, parent) { if (root === -1) { + // logger { logger.println('No more nodes. Backtracking.'); Tracer.delay(); + // } return; } + // visualize { logger.println(`Reached ${root}`); treeTracer.visit(root, parent); Tracer.delay(); logger.println(` Going left from ${root}`); Tracer.delay(); + // } postOrder(T[root][0], root); + // logger { logger.println(` Going right from ${root}`); Tracer.delay(); + // } postOrder(T[root][1], root); + // visualize { logger.println(`Printing ${root}`); treeTracer.leave(root); arrayTracer.patch(index++, root); Tracer.delay(); + // } } postOrder(5); // node with key 5 is the root +// logger { logger.println('Finished'); +// visualize { diff --git a/Brute Force/Binary Tree Traversal/preOrder.js b/Brute Force/Binary Tree Traversal/preOrder.js index 67c110b2..ccd0f4b5 100644 --- a/Brute Force/Binary Tree Traversal/preOrder.js +++ b/Brute Force/Binary Tree Traversal/preOrder.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,6 +30,7 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer('Traversal Pre-order'); const arrayTracer = new Array1DTracer('Print Pre-order'); const logger = new LogTracer('Log'); @@ -36,16 +39,20 @@ treeTracer.set(G); treeTracer.layoutTree(5); arrayTracer.set(new Array(T.length).fill('-')); Tracer.delay(); +// } let index = 0; function preOrder(root, parent) { if (root === -1) { + // logger { logger.println('No more nodes. Backtracking.'); Tracer.delay(); + // } return; } + // visualize { logger.println(`Reached ${root}`); treeTracer.visit(root, parent); Tracer.delay(); @@ -57,12 +64,17 @@ function preOrder(root, parent) { logger.println(` Going left from ${root}`); Tracer.delay(); + // } preOrder(T[root][0], root); + // logger { logger.println(` Going right from ${root}`); Tracer.delay(); + // } preOrder(T[root][1], root); } preOrder(5); // node with key 5 is the root +// logger { logger.println('Finished'); +// } diff --git a/Brute Force/Bipartiteness Test/code.js b/Brute Force/Bipartiteness Test/code.js index 3e36f342..62d4e4ec 100644 --- a/Brute Force/Bipartiteness Test/code.js +++ b/Brute Force/Bipartiteness Test/code.js @@ -1,8 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); - -const tracer = new GraphTracer().directed(false); -const logger = new LogTracer(); -tracer.log(logger); +// } const G = [ [0, 1, 0, 1, 1], @@ -11,11 +9,16 @@ const G = [ [1, 0, 1, 0, 0], // <-- replace latest 0 with 1 to make G not biparted [1, 0, 0, 0, 0], ]; -tracer.set(G); +// define tracer variables { +const tracer = new GraphTracer().directed(false); +const logger = new LogTracer(); +tracer.log(logger); +tracer.set(G); const colorsTracer = new Array1DTracer('Colors'); Layout.setRoot(new VerticalLayout([tracer, logger, colorsTracer])); Tracer.delay(); +// } function BFSCheckBipartiteness(s) { const Q = []; @@ -23,36 +26,50 @@ function BFSCheckBipartiteness(s) { // Create a new matrix to set colors (0,1) const Colors = []; for (let _i = 0; _i < G.length; _i++) Colors[_i] = -1; + // visualize { colorsTracer.set(Colors); + // } Colors[s] = 1; + // visualize { colorsTracer.patch(s, 1); + // } Q.push(s); // add start node to queue while (Q.length > 0) { const node = Q.shift(); // dequeue + // visualize { tracer.visit(node); Tracer.delay(); + // } for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { if (Colors[i] === -1) { Colors[i] = 1 - Colors[node]; + // visualize { colorsTracer.patch(i, 1 - Colors[node]); + // } Q.push(i); + // visualize { tracer.visit(i, node); Tracer.delay(); + // } } else if (Colors[i] === Colors[node]) { + // logger { logger.println('Graph is not biparted'); + // } return false; } } } } + // logger { logger.println('Graph is biparted'); + // } return true; } diff --git a/Brute Force/Breadth-First Search/shortestPath.js b/Brute Force/Breadth-First Search/shortestPath.js index bee38433..0875ad82 100644 --- a/Brute Force/Breadth-First Search/shortestPath.js +++ b/Brute Force/Breadth-First Search/shortestPath.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,6 +10,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function BFS() { const W = []; // W[i] indicates the length of the shortest path from start node to the i-th node @@ -14,12 +18,16 @@ function BFS() { let i; for (i = 0; i < G.length; i++) { W.push(MAX_VALUE); + // visualize { tracer.updateNode(i, MAX_VALUE); + // } } W[s] = 0; Q.push(s); // add start node to queue + // visualize { tracer.visit(s, undefined, 0); Tracer.delay(); + // } while (Q.length > 0) { const node = Q.shift(); // dequeue for (i = 0; i < G[node].length; i++) { @@ -27,8 +35,10 @@ function BFS() { if (W[i] > W[node] + G[node][i]) { // if current path is shorter than the previously shortest path W[i] = W[node] + G[node][i]; // update the length of the shortest path Q.push(i); // add child node to queue + // visualize { tracer.visit(i, node, W[i]); Tracer.delay(); + // } } } } @@ -42,10 +52,14 @@ do { e = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (s === e); let MAX_VALUE = 0x7fffffff; +// logger { logger.println(`finding the shortest path from ${s} to ${e}`); +// } const minWeight = BFS(s); +// logger { if (minWeight === MAX_VALUE) { logger.println(`there is no path from ${s} to ${e}`); } else { logger.println(`the shortest path from ${s} to ${e} is ${minWeight}`); } +// } diff --git a/Brute Force/Breadth-First Search/tree.js b/Brute Force/Breadth-First Search/tree.js index 598a7dd1..f2c8411b 100644 --- a/Brute Force/Breadth-First Search/tree.js +++ b/Brute Force/Breadth-First Search/tree.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -tracer.log(logger); -Layout.setRoot(new VerticalLayout([tracer, logger])); const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], @@ -17,22 +15,33 @@ const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +tracer.log(logger); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); tracer.layoutTree(0); Tracer.delay(); +// } function BFS(s) { // s = start node const Q = []; Q.push(s); // add start node to queue + // visualize { tracer.visit(s); Tracer.delay(); + // } while (Q.length > 0) { const node = Q.shift(); // dequeue for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if current node has the i-th node as a child Q.push(i); // add child node to queue + // visualize { tracer.visit(i, node); Tracer.delay(); + // } } } } diff --git a/Brute Force/Bridge Finding/efficient.js b/Brute Force/Bridge Finding/efficient.js index a9c05b83..9864d2b2 100644 --- a/Brute Force/Bridge Finding/efficient.js +++ b/Brute Force/Bridge Finding/efficient.js @@ -1,8 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const graphTracer = new GraphTracer().directed(false); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([graphTracer, logger])); const G = [ [0, 1, 0, 0, 1, 0], [1, 0, 0, 0, 1, 0], @@ -12,8 +11,13 @@ const G = [ [0, 0, 0, 1, 0, 0], ]; +// define tracer variables { +const graphTracer = new GraphTracer().directed(false); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([graphTracer, logger])); graphTracer.set(G); Tracer.delay(); +// } /* NOTE: Code assumes NO parallel edges @@ -29,56 +33,74 @@ const util = (u, disc, low, parent) => { // disc is the numbering of the vertices in the DFS, starting at 0 // low[v] is the lowest numbered vertex that can be reached from vertex v along the DFS // parent is the node that u came from + // visualize { logger.println(''); logger.println(`Visiting node ${u}`); graphTracer.visit(u); Tracer.delay(); graphTracer.leave(u); Tracer.delay(); + // } // visited [u] = true; disc[u] = low[u] = timer++; + // logger { logger.println(`Nodes adjacent to ${u} are: [ ${adj[u]} ]`); + // } /* adj [u].forEach (function (v) { graphTracer.visit (v, u).delay (); graphTracer.leave (v, u).delay (); }); */ const trace = (v) => { + // visualize { graphTracer.visit(v, u); Tracer.delay(); graphTracer.leave(v, u); Tracer.delay(); + // } }; adj[u].forEach((v) => { if (disc[v] > -1 && v === parent) { trace(v); + // logger { logger.println(`${u}'s neighbor ${v} is u's parent. Not visiting it.`); + // } } else if (disc[v] > -1 && v !== parent) { trace(v); + // logger { logger.println(`${u}'s neighbor ${v} is not u's parent. Comparing low[u] with disc[v]`); + // } if (low[u] > disc[v]) { + // logger { logger.println(`low[${u}] is greater than disc[${v}]. Setting low[${u}] to disc[${v}]`); + // } low[u] = disc[v]; } } if (disc[v] === -1) { trace(v); + // logger { logger.println(`${u}'s neighbor ${v} has not been visited yet`); logger.println(`recursively calling util (${v}, [${disc}], [${low}],${u})`); + // } util(v, disc, low, u); + // logger { logger.println('--------------------------------------------------------------------'); logger.println(`Setting low [${u}] to ${Math.min(low[u], low[v])}`); + // } low[u] = Math.min(low[u], low[v]); if (low[v] === disc[v]) { + // logger { logger.println(`low [${v}] === disc [${v}], low[${v}]=${low[v]}, disc[${v}]=${disc[v]}`); logger.println(`${u} -> ${v} is a bridge. Adding ${u}->${v}to the set of bridges found`); + // } bridges.push([u, v]); } } @@ -104,6 +126,7 @@ const util = (u, disc, low, parent) => { }); }()); + // logger { logger.println(`Initializing: disc: ${disc} low: ${low}`); logger.println(''); logger.println('Beginning efficient Bridge Finding'); @@ -111,17 +134,24 @@ const util = (u, disc, low, parent) => { logger.println(''); logger.println('Starting the main for loop (for each node)'); + // } for (let v = 0; v < graph.length; v++) { if (disc[v] === -1) { + // logger { logger.println(`${v} has not been visited yet. Calling util (${v}, [${disc}], [${low}],${v}) from the for loop`); + // } util(v, disc, low, v); + // logger { logger.println(`Returned in for loop after util (${v}, [${disc}], [${low}], [${v}])`); + // } } } }(G)); +// logger { logger.println(`There are ${bridges.length} bridges in the Graph`); for (let i = 0; i < bridges.length; i++) { logger.println(`${bridges[i][0]}-->${bridges[i][1]}`); } logger.println('NOTE: All bridges are both ways (just like in the Naive Algorithm) because the Graph is undirected. So, edge A->B and B->A, both are bridges'); +// } diff --git a/Brute Force/Bridge Finding/naive.js b/Brute Force/Bridge Finding/naive.js index c8ab7d14..4dd4233b 100644 --- a/Brute Force/Bridge Finding/naive.js +++ b/Brute Force/Bridge Finding/naive.js @@ -1,8 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer().directed(false); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); const G = [ [0, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 0], @@ -12,8 +11,13 @@ const G = [ [0, 0, 0, 1, 0, 0], ]; +// define tracer variables { +const tracer = new GraphTracer().directed(false); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); Tracer.delay(); +// } // Depth First Search Exploration Algorithm to test connectedness of the Graph (see Graph Algorithms/DFS/exploration), without the tracer & logger commands function DFSExplore(graph, source) { @@ -51,11 +55,13 @@ function findBridges(graph) { for (let i = 0; i < graph.length; i++) { for (let j = 0; j < graph.length; j++) { if (graph[i][j]) { // check if an edge exists + // visualize { logger.println(`Deleting edge ${i}->${j} and calling DFSExplore ()`); tracer.visit(j, i); Tracer.delay(); tracer.leave(j, i); Tracer.delay(); + // } tempGraph = JSON.parse(JSON.stringify(graph)); tempGraph[i][j] = 0; @@ -63,9 +69,13 @@ function findBridges(graph) { visited = DFSExplore(tempGraph, 0); if (Object.keys(visited).length === graph.length) { + // logger { logger.println('Graph is CONNECTED. Edge is NOT a bridge'); + // } } else { + // logger { logger.println('Graph is DISCONNECTED. Edge IS a bridge'); + // } bridges.push([i, j]); } } @@ -77,8 +87,10 @@ function findBridges(graph) { const bridges = findBridges(G); +// logger { logger.println('The bridges are: '); for (const i in bridges) { logger.println(`${bridges[i][0]} to ${bridges[i][1]}`); } logger.println('NOTE: A bridge is both ways, i.e., from A to B and from B to A, because this is an Undirected Graph'); +// } diff --git a/Brute Force/Bubble Sort/code.js b/Brute Force/Bubble Sort/code.js index 136f7c97..a69ae686 100644 --- a/Brute Force/Bubble Sort/code.js +++ b/Brute Force/Bubble Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,32 +11,49 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } let N = D.length; let swapped; do { swapped = false; + // visualize { tracer.select(N - 1); Tracer.delay(); + // } for (let i = 1; i < N; i++) { + // visualize { tracer.select(i); Tracer.delay(); + // } if (D[i - 1] > D[i]) { + // logger { logger.println(`swap ${D[i - 1]} and ${D[i]}`); + // } const temp = D[i - 1]; D[i - 1] = D[i]; D[i] = temp; swapped = true; + // visualize { tracer.patch(i - 1, D[i - 1]); tracer.patch(i, D[i]); Tracer.delay(); tracer.depatch(i - 1); tracer.depatch(i); + // } } + // visualize { tracer.deselect(i); + // } } + // visualize { tracer.deselect(N - 1); + // } N--; } while (swapped); +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Comb Sort/code.js b/Brute Force/Comb Sort/code.js index fbbdbf89..6d3bc2ae 100644 --- a/Brute Force/Comb Sort/code.js +++ b/Brute Force/Comb Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } const N = D.length; let swapped; let gap = N; // initialize gap size @@ -26,26 +32,34 @@ do { swapped = false; // initialize swapped // a single comb over the input list for (let i = 0; i + gap < N; i++) { + // visualize { tracer.select(i); tracer.select(i + gap); Tracer.delay(); + // } if (D[i] > D[i + gap]) { + // logger { logger.println(`swap ${D[i]} and ${D[i + gap]}`); // log swap event - + // } + const temp = D[i]; D[i] = D[i + gap]; D[i + gap] = temp; + // visualize { tracer.patch(i, D[i]); tracer.patch(i + gap, D[i + gap]); Tracer.delay(); tracer.depatch(i); tracer.depatch(i + gap); + // } swapped = true; // Flag swapped has happened and list is not guaranteed sorted } + // visualize { tracer.deselect(i); tracer.deselect(i + gap); + // } } // End of combing } while (gap !== 1 || swapped); diff --git a/Brute Force/Cycle Sort/code.js b/Brute Force/Cycle Sort/code.js index 8bc185d2..9dac822a 100644 --- a/Brute Force/Cycle Sort/code.js +++ b/Brute Force/Cycle Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } const N = D.length; let writes = 0; // number of writing performed let pos; // the index of item in the sorted array @@ -20,12 +26,16 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { // find where to put the item pos = cycleStart; + // visualize { tracer.select(cycleStart); + // } for (let i = cycleStart + 1; i <= N - 1; i++) { + // visualize { tracer.select(i); Tracer.delay(); tracer.deselect(i); + // } if (D[i] < item) { pos++; } @@ -33,7 +43,9 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { // if the item is already there, this is not a circle if (pos === cycleStart) { + // visualize { tracer.deselect(cycleStart); + // } continue; } @@ -49,11 +61,14 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { writes++; + // logger { if (pos !== cycleStart) { logger.println(`Rewrite ${D[pos]} to index ${pos}; the next value to rewrite is ${item}`); } else { logger.println(`Rewrite ${D[pos]} to index ${pos}`); } + // } + // visualize { tracer.select(pos); Tracer.delay(); tracer.deselect(pos); @@ -62,15 +77,18 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { Tracer.delay(); tracer.depatch(pos); tracer.depatch(cycleStart); + // } // rotate the rest of the cycle while (pos !== cycleStart) { pos = cycleStart; for (let i = cycleStart + 1; i <= N - 1; i++) { + // visualize { tracer.select(i); Tracer.delay(); tracer.deselect(i); + // } if (D[i] < item) { pos++; } @@ -84,11 +102,14 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { D[pos] = item; item = temp; + // logger { if (pos !== cycleStart) { logger.println(`Rewrite ${D[pos]} to index ${pos}; the next value to rewrite is ${item}`); } else { logger.println(`Rewrite ${D[pos]} to index ${pos}`); } + // } + // visualize { tracer.select(pos); Tracer.delay(); tracer.deselect(pos); @@ -97,9 +118,12 @@ for (let cycleStart = 0; cycleStart <= N - 2; cycleStart++) { Tracer.delay(); tracer.depatch(pos); tracer.depatch(cycleStart); + // } writes++; } } +// logger { logger.println(`Number of writes performed is ${writes}`); +// } diff --git a/Brute Force/Depth-First Search/graph.js b/Brute Force/Depth-First Search/graph.js index eb7881de..07660a77 100644 --- a/Brute Force/Depth-First Search/graph.js +++ b/Brute Force/Depth-First Search/graph.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const graphTracer = new GraphTracer().directed(false); const visitedTracer = new Array1DTracer('visited'); const logger = new LogTracer(); @@ -8,6 +11,7 @@ graphTracer.log(logger); const G = Randomize.Graph({ N: 8, ratio: .3, directed: false }); graphTracer.set(G); Tracer.delay(); +// } function DFSExplore(graph, source) { const stack = [[source, null]]; @@ -19,7 +23,9 @@ function DFSExplore(graph, source) { for (i = 0; i < graph.length; i++) { visited.push(false); } + // visualize { visitedTracer.set(visited); + // } while (stack.length > 0) { temp = stack.pop(); @@ -28,6 +34,7 @@ function DFSExplore(graph, source) { if (!visited[node]) { visited[node] = true; + // visualize { visitedTracer.patch(node, visited[node]); if (prev !== undefined && graph[node][prev]) { @@ -37,6 +44,7 @@ function DFSExplore(graph, source) { graphTracer.visit(node); Tracer.delay(); } + // } for (i = 0; i < graph.length; i++) { if (graph[node][i]) { @@ -52,8 +60,10 @@ function DFSExplore(graph, source) { const visited = DFSExplore(G, 0); let check = true; for (let i = 0; i < visited.length; i++) check &= visited[i]; +// logger { if (check) { logger.println('The Graph is CONNECTED'); } else { logger.println('The Graph is NOT CONNECTED'); } +// } diff --git a/Brute Force/Depth-First Search/shortestPath.js b/Brute Force/Depth-First Search/shortestPath.js index 9403fc24..646b865c 100644 --- a/Brute Force/Depth-First Search/shortestPath.js +++ b/Brute Force/Depth-First Search/shortestPath.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,22 +10,29 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function DFS(node, parent, weight) { // node = current node, parent = previous node if (minWeight < weight) return; if (node === e) { + // visualize { tracer.visit(node, parent, weight); Tracer.delay(); + // } if (minWeight > weight) { minWeight = weight; } + // visualize { tracer.leave(node, parent, minWeight); Tracer.delay(); + // } return; } D[node] = true; // label current node as discovered + // visualize { tracer.visit(node, parent, weight); Tracer.delay(); + // } for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if the path from current node to the i-th node exists if (!D[i]) { // if the i-th node is not labeled as discovered @@ -31,8 +41,10 @@ function DFS(node, parent, weight) { // node = current node, parent = previous n } } D[node] = false; // label current node as undiscovered + // visualize { tracer.leave(node, parent, 0); Tracer.delay(); + // } } const s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node @@ -42,12 +54,16 @@ do { } while (s === e); const MAX_VALUE = Infinity; let minWeight = MAX_VALUE; +// logger { logger.println(`finding the shortest path from ${s} to ${e}`); +// } let D = []; // D[i] indicates whether the i-th node is discovered or not for (let i = 0; i < G.length; i++) D.push(false); DFS(s, undefined, 0); +// logger { if (minWeight === MAX_VALUE) { logger.println(`there is no path from ${s} to ${e}`); } else { logger.println(`the shortest path from ${s} to ${e} is ${minWeight}`); } +// } diff --git a/Brute Force/Depth-First Search/tree.js b/Brute Force/Depth-First Search/tree.js index 4d9a3508..a582c529 100644 --- a/Brute Force/Depth-First Search/tree.js +++ b/Brute Force/Depth-First Search/tree.js @@ -1,9 +1,7 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new GraphTracer(); -const logger = new LogTracer(); -tracer.log(logger); -Layout.setRoot(new VerticalLayout([tracer, logger])); const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], @@ -17,13 +15,22 @@ const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]; + +// define tracer variables { +const tracer = new GraphTracer(); +const logger = new LogTracer(); +tracer.log(logger); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); tracer.layoutTree(0); Tracer.delay(); +// } function DFS(node, parent) { // node = current node, parent = previous node + // visualize {/ tracer.visit(node, parent); Tracer.delay(); + // } for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if current node has the i-th node as a child DFS(i, node); // recursively call DFS diff --git a/Brute Force/Depth-First Search/weightedGraph.js b/Brute Force/Depth-First Search/weightedGraph.js index c71549af..b57b1f0b 100644 --- a/Brute Force/Depth-First Search/weightedGraph.js +++ b/Brute Force/Depth-First Search/weightedGraph.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,12 +10,15 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } let D; // D[i] indicates whether the i-th node is discovered or not function DFS(node, parent, weight) { // node = current node, parent = previous node + // visualize { tracer.visit(node, parent, weight); Tracer.delay(); + // } D[node] = true; // label current node as discovered for (let i = 0; i < G[node].length; i++) { if (G[node][i]) { // if the edge from current node to the i-th node exists @@ -22,12 +28,16 @@ function DFS(node, parent, weight) { // node = current node, parent = previous n } } D[node] = false; // label current node as undiscovered + // visualize { tracer.leave(node, parent, 0); Tracer.delay(); + // } } for (let i = 0; i < G.length; i++) { // start from every node + // logger { logger.println(`start from ${i}`); + // } D = []; for (let j = 0; j < G.length; j++) D.push(false); DFS(i, undefined, 0); diff --git a/Brute Force/Flood Fill/code.js b/Brute Force/Flood Fill/code.js index f6b17a26..316b5fff 100644 --- a/Brute Force/Flood Fill/code.js +++ b/Brute Force/Flood Fill/code.js @@ -1,7 +1,7 @@ +// import visualization libraries { const { Tracer, Array2DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array2DTracer(); -Layout.setRoot(new VerticalLayout([tracer])); const G = [ ['#', '#', '#', '#', '#', '#', '#', '#', '#'], ['#', '-', '-', '-', '#', '-', '-', '-', '#'], @@ -13,8 +13,13 @@ const G = [ ['#', '-', '-', '-', '#', '-', '-', '-', '#'], ['#', '#', '#', '#', '#', '#', '#', '#', '#'], ]; + +// define tracer variables { +const tracer = new Array2DTracer(); +Layout.setRoot(new VerticalLayout([tracer])); tracer.set(G); Tracer.delay(); +// } function FloodFill(i, j, oldColor, newColor) { if (i < 0 || i >= G.length || j < 0 || j >= G[i].length) return; @@ -23,10 +28,12 @@ function FloodFill(i, j, oldColor, newColor) { // set the color of node to newColor G[i][j] = newColor; + // visualize { tracer.select(i, j); Tracer.delay(); tracer.patch(i, j, G[i][j]); Tracer.delay(); + // } // next step four-way FloodFill(i + 1, j, oldColor, newColor); diff --git a/Brute Force/Heapsort/code.js b/Brute Force/Heapsort/code.js index 73832cb8..d0abb120 100644 --- a/Brute Force/Heapsort/code.js +++ b/Brute Force/Heapsort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 10 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`Original array = [${D.join(', ')}]`); +// } function heapSort(array, size) { let i; @@ -25,6 +31,7 @@ function heapSort(array, size) { array[0] = array[j]; array[j] = temp; + // visualize { tracer.patch(0, array[0]); tracer.patch(j, array[j]); logger.println(`Swapping elements : ${array[0]} & ${array[j]}`); @@ -33,10 +40,13 @@ function heapSort(array, size) { tracer.depatch(j); tracer.select(j); Tracer.delay(); + // } heapify(array, j, 0); + // visualize { tracer.deselect(j); + // } } } @@ -59,12 +69,14 @@ function heapify(array, size, root) { array[root] = array[largest]; array[largest] = temp; + // visualize { tracer.patch(root, array[root]); tracer.patch(largest, array[largest]); logger.println(`Swapping elements : ${array[root]} & ${array[largest]}`); Tracer.delay(); tracer.depatch(root); tracer.depatch(largest); + // } heapify(array, size, largest); } @@ -72,4 +84,6 @@ function heapify(array, size, root) { heapSort(D, D.length); +// logger { logger.println(`Final array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Insertion Sort/code.js b/Brute Force/Insertion Sort/code.js index 462a66cd..7b3db3d0 100644 --- a/Brute Force/Insertion Sort/code.js +++ b/Brute Force/Insertion Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,24 +11,35 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } for (let i = 1; i < D.length; i++) { const key = D[i]; + // visualize { logger.println(`insert ${key}`); tracer.select(i); Tracer.delay(); + // } let j; for (j = i - 1; (j >= 0) && (D[j] > key); j--) { D[j + 1] = D[j]; + // visualize { tracer.patch(j + 1, D[j + 1]); Tracer.delay(); tracer.depatch(j + 1); + // } } D[j + 1] = key; + // visualize { tracer.patch(j + 1, D[j + 1]); Tracer.delay(); tracer.depatch(j + 1); tracer.deselect(i); + // } } +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Lowest Common Ancestor/code.js b/Brute Force/Lowest Common Ancestor/code.js index 309a4881..b3b8df64 100644 --- a/Brute Force/Lowest Common Ancestor/code.js +++ b/Brute Force/Lowest Common Ancestor/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ // G[i][j] indicates whether the path from the i-th node to the j-th node exists or not [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -28,23 +30,31 @@ const T = [ // mapping to G as a binary tree , [i][0] indicates left child, [i][ [9, -1], ]; +// define tracer variables { const treeTracer = new GraphTracer(' Traversal Pre-order '); const logger = new LogTracer(' Log '); Layout.setRoot(new VerticalLayout([treeTracer, logger])); treeTracer.set(G); treeTracer.layoutTree(5); Tracer.delay(); +// } function lcaBT(parent, root, a, b) { + // logger { logger.println(`Beginning new Iteration of lcaBT () with parent: ${parent}, current root: ${root}`); + // } if (root === -1) { + // logger { logger.println('Reached end of path & target node(s) not found'); + // } return null; } + // visualize { if (parent !== null) treeTracer.visit(root, parent); else treeTracer.visit(root); Tracer.delay(); + // visualize { if (root === a || root === b) return root; @@ -53,8 +63,10 @@ function lcaBT(parent, root, a, b) { if (left !== null && right !== null) return root; if (left === null && right === null) { + // visualize { treeTracer.leave(root, parent); Tracer.delay(); + // } } return (left !== null ? left : right); @@ -62,4 +74,6 @@ function lcaBT(parent, root, a, b) { const a = 7; const b = 2; +// logger { logger.println(`Lowest common ancestor of ${a} & ${b} is: ${lcaBT(null, 5, a, b)}`); +// } diff --git a/Brute Force/PageRank/code.js b/Brute Force/PageRank/code.js index 69e9c82d..8332c37c 100644 --- a/Brute Force/PageRank/code.js +++ b/Brute Force/PageRank/code.js @@ -1,9 +1,12 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } function filledArray(length, value) { return Array(...Array(length)).map(Number.prototype.valueOf, value); } +// define tracer variables { const G = Randomize.Graph({ N: 5, ratio: .4 }); let ranks; const outgoingEdgeCounts = filledArray(G.length, 0); @@ -22,6 +25,7 @@ oecTracer.set(outgoingEdgeCounts); for (incomingNodes = []; incomingNodes.length < G.length; incomingNodes.push(filledArray(G.length, -1))) ; inTracer.set(incomingNodes); Tracer.delay(); +// } /* PageRank Algorithm Version 2 @@ -41,40 +45,51 @@ function arraySum(array) { function showOutgoingEdges(i) { G[i].forEach((edgeExists, j) => { if (edgeExists) { + // visualize { graphTracer.visit(j, i); Tracer.delay(); graphTracer.leave(j, i); Tracer.delay(); + // } } }); } // PRECOMPUTATIONS +// logger { logger.println('Calculate Outgoing Edge Count for each Node'); +// } (function calculateOEC() { G.forEach((relations, i) => { outgoingEdgeCounts[i] = arraySum(relations); showOutgoingEdges(i); + // visualize { oecTracer.patch(i, outgoingEdgeCounts[i]); Tracer.delay(); oecTracer.depatch(i); Tracer.delay(); + // } }); }()); +// logger { logger.println('determine incoming nodes for each node'); +// } (function determineIN() { for (let i = 0; i < G.length; i++) { for (let j = 0; j < G.length; j++) { if (G[i][j]) { // there's an edge FROM i TO j + // visualize { graphTracer.visit(j, i); Tracer.delay(); + // } const nextPos = incomingNodes[j].indexOf(-1); incomingNodes[j][nextPos] = i; + // visualize { inTracer.patch(j, nextPos, i); Tracer.delay(); inTracer.depatch(j, nextPos); @@ -82,6 +97,7 @@ logger.println('determine incoming nodes for each node'); graphTracer.leave(j, i); Tracer.delay(); + // } } } } @@ -96,27 +112,37 @@ function updateRank(nodeIndex) { let inNodeSummation = 0; let result; + // logger { logger.println(`Updating rank of ${nodeIndex}`); logger.println(`The incoming Nodes of ${nodeIndex} are being highlighted`); + // } incomingNodes[nodeIndex].forEach((incoming, i) => { + // visualize { inTracer.select(nodeIndex, i); Tracer.delay(); logger.println(`Outgoing edge count of ${incoming} is ${outgoingEdgeCounts[incoming]}`); oecTracer.select(incoming); Tracer.delay(); + // } inNodeSummation += (ranks[incoming] / outgoingEdgeCounts[incoming]); + // visualize { oecTracer.deselect(incoming); Tracer.delay(); inTracer.deselect(nodeIndex, i); Tracer.delay(); + // } }); + // logger { logger.println(`In-Node summation of ${nodeIndex} = ${inNodeSummation}`); - + // } + result = ((1 - damping) / G.length) + (damping * inNodeSummation); // notice the subtle difference between equations of Basic PR & PR version 2 (divide by N) + // logger { logger.println(`Therefore, using Equation, new rank of ${nodeIndex} = ${result}`); + // } return result; } @@ -124,27 +150,37 @@ let damping = 0.85; let iterations = 7; const initialRank = 1.0; +// logger { logger.println(`Initialized all Page ranks to ${initialRank}`); +// } ranks = filledArray(G.length, initialRank); +// visualize { rankTracer.set(ranks); +// } +// logger { logger.println('Begin execution of PageRank Version #1'); logger.println('Equation used: PR (X) = (1 - D) + D (In-Node-Summation i->X (PR (I) / Out (i)))'); logger.println('D = Damping Factor, PR (X) = Page rank of Node X, i = the ith In-Node of X, Out (i) = outgoing Edge Count of i'); logger.println(''); +// } while (iterations--) { for (let node = 0; node < ranks.length; node++) { ranks[node] = updateRank(node); + // visualize { rankTracer.patch(node, ranks[node]); Tracer.delay(); rankTracer.patch(node); Tracer.delay(); + // } } } +// logger { logger.println('Page Ranks have been converged to.'); ranks.forEach((rank, node) => { logger.println(`Rank of Node #${node} = ${rank}`); }); logger.println('Done'); +// } diff --git a/Brute Force/Pancake Sort/code.js b/Brute Force/Pancake Sort/code.js index f520a64a..4e066872 100644 --- a/Brute Force/Pancake Sort/code.js +++ b/Brute Force/Pancake Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,43 +11,63 @@ const D = Randomize.Array1D({ N: 10 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } const N = D.length; function flip(start) { + // visualize { tracer.select(start, N - 1); Tracer.delay(); + // } let idx = 0; for (let i = start; i < (start + N) / 2; i++) { + // visualize { tracer.select(i); Tracer.delay(); + // } const temp = D[i]; D[i] = D[N - idx - 1]; D[N - idx - 1] = temp; + // visualize { tracer.patch(i, D[i]); tracer.patch(N - idx - 1, D[N - idx - 1]); Tracer.delay(); tracer.depatch(i); tracer.depatch(N - idx - 1); tracer.deselect(i); + // } idx++; } + // visualize { tracer.deselect(start, N - 1); + // } } for (let i = 0; i < N - 1; i++) { + // logger { logger.println(`round ${i + 1}`); + // } const currArr = D.slice(i, N); const currMax = currArr.reduce((prev, curr, idx) => ((curr > prev.val) ? { idx, val: curr } : prev), { idx: 0, val: currArr[0], }); if (currMax.idx !== 0) { // if currMax.idx === 0 that means max element already at the bottom, no flip required + // logger { logger.println(`flip at ${currMax.idx + i} (step 1)`); + // } flip(currMax.idx + i, N); + // logger { logger.println(`flip at ${i} (step 2)`); + // } flip(i, N); } } + +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Rabin-Karp's String Search/code.js b/Brute Force/Rabin-Karp's String Search/code.js index 7ede6390..ef9d1e58 100644 --- a/Brute Force/Rabin-Karp's String Search/code.js +++ b/Brute Force/Rabin-Karp's String Search/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const text = ['h', 'e', 'l', 'l', 'o', ' ', 's', 'i', 'r', ' ', 'h', 'e', 'l', 'l', 'o']; const pattern = ['h', 'e', 'l', 'l', 'o']; @@ -6,6 +8,7 @@ const pattern = ['h', 'e', 'l', 'l', 'o']; const Q = 101; // A prime number const D = 256; // number of characters in the input alphabet +// define tracer variables { const logger = new LogTracer(); const tracer1 = new Array1DTracer('Text'); const tracer2 = new Array1DTracer('Pattern'); @@ -13,6 +16,7 @@ Layout.setRoot(new VerticalLayout([logger, tracer1, tracer2])); tracer1.set(text); tracer2.set(pattern); Tracer.delay(); +// } const N = text.length; const M = pattern.length; @@ -38,27 +42,35 @@ for (let i = 0; i <= N - M; i++) { */ if (hashPattern === hashText) { let f = 0; + // visualize { tracer1.select(i, i + M - 1); Tracer.delay(); tracer2.select(0, M - 1); Tracer.delay(); + // } for (let j = 0; j < M; j++) { + // visualize { tracer1.patch(i + j); Tracer.delay(); tracer2.patch(j); Tracer.delay(); + // } if (text[i + j] !== pattern[j]) { f++; } + // visualize { tracer1.depatch(i + j); tracer2.depatch(j); + // } } + // visualize { if (f === 0) { logger.println(` Pattern found at index ${i}`); } tracer1.deselect(i, i + M); tracer2.deselect(0, M - 1); + // } } /* diff --git a/Brute Force/Selection Sort/code.js b/Brute Force/Selection Sort/code.js index d7316338..41af8a11 100644 --- a/Brute Force/Selection Sort/code.js +++ b/Brute Force/Selection Sort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,34 +11,53 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } for (let i = 0; i < D.length - 1; i++) { let minJ = i; + // visualize { tracer.select(i); Tracer.delay(); + // } for (let j = i + 1; j < D.length; j++) { + // visualize { tracer.select(j); Tracer.delay(); + // } if (D[j] < D[minJ]) { minJ = j; + // visualize { tracer.patch(j); Tracer.delay(); tracer.depatch(j); + // } } + // visualize { tracer.deselect(j); + // } } if (minJ !== i) { + // logger { logger.println(`swap ${D[i]} and ${D[minJ]}`); + // } const temp = D[i]; D[i] = D[minJ]; D[minJ] = temp; + // visualize { tracer.patch(i, D[i]); tracer.patch(minJ, D[minJ]); Tracer.delay(); tracer.depatch(i); tracer.depatch(minJ); + // } } + // visualize { tracer.deselect(i); + // } } +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Shellsort/code.js b/Brute Force/Shellsort/code.js index d13739be..333ad2ce 100644 --- a/Brute Force/Shellsort/code.js +++ b/Brute Force/Shellsort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,29 +11,43 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`Original array = [${D.join(', ')}]`); +// } const N = D.length; for (let gap = N; gap = parseInt(gap / 2);) { + // logger { logger.println(''); logger.println(`Gap of ${gap}`); + // } for (let i = gap; i < N; i++) { + // visualize { tracer.select(i); tracer.select(i - gap); Tracer.delay(); + // } const k = D[i]; + // logger { logger.println(`Holding: ${k}`); + // } let j; for (j = i; j >= gap && k < D[j - gap]; j -= gap) { + // logger { logger.println(`${k} < ${D[j - gap]}`); + // } D[j] = D[j - gap]; + // visualize { tracer.patch(j, D[j]); Tracer.delay(); tracer.depatch(j); + // } } const old = D[j]; D[j] = k; + // visualize { if (old !== k) { tracer.patch(j, D[j]); Tracer.delay(); @@ -40,7 +57,10 @@ for (let gap = N; gap = parseInt(gap / 2);) { tracer.deselect(i); tracer.deselect(i - gap); + // } } } +// logger { logger.println(''); logger.println(`Sorted array = [${D.join(', ')}]`); +// } diff --git a/Brute Force/Tarjan's Strongly Connected Components/code.js b/Brute Force/Tarjan's Strongly Connected Components/code.js index 0bcc0c63..415c5838 100644 --- a/Brute Force/Tarjan's Strongly Connected Components/code.js +++ b/Brute Force/Tarjan's Strongly Connected Components/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const G = [ [0, 0, 1, 1, 0, 0], @@ -9,16 +11,6 @@ const G = [ [0, 0, 0, 0, 1, 0], ]; -const graphTracer = new GraphTracer(); -graphTracer.set(G); - -const discTracer = new Array1DTracer('Disc'); -const lowTracer = new Array1DTracer('Low'); -const stackMemberTracer = new Array1DTracer('stackMember'); -const stTracer = new Array1DTracer('st'); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([graphTracer, discTracer, lowTracer, stackMemberTracer, stTracer, logger])); - const disc = new Array(G.length); const low = new Array(G.length); const stackMember = new Array(G.length); @@ -31,31 +23,51 @@ for (let i = 0; i < G.length; i++) { stackMember[i] = false; } +// define tracer variables { +const graphTracer = new GraphTracer(); +graphTracer.set(G); +const discTracer = new Array1DTracer('Disc'); +const lowTracer = new Array1DTracer('Low'); +const stackMemberTracer = new Array1DTracer('stackMember'); +const stTracer = new Array1DTracer('st'); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([graphTracer, discTracer, lowTracer, stackMemberTracer, stTracer, logger])); discTracer.set(disc); lowTracer.set(low); stackMemberTracer.set(stackMember); stTracer.set(st); Tracer.delay(); +// } function SCCVertex(u, disc, low, st, stackMember, carry) { + // visualize { graphTracer.visit(u); Tracer.delay(); + // } disc[u] = ++carry.time; + // visualize { discTracer.patch(u, carry.time); Tracer.delay(); + // } low[u] = carry.time; + // visualize { lowTracer.patch(u, carry.time); Tracer.delay(); + // } st.push(u); + // visualize { stTracer.set(st); Tracer.delay(); + // } stackMember[u] = true; + // visualize { stackMemberTracer.patch(u, true); Tracer.delay(); + // } // Go through all vertices adjacent to this for (let v = 0; v < G[u].length; v++) { @@ -67,15 +79,20 @@ function SCCVertex(u, disc, low, st, stackMember, carry) { // Check if the subtree rooted with 'v' has a // connection to one of the ancestors of 'u' low[u] = Math.min(low[u], low[v]); + // visualize { lowTracer.patch(u, low[u]); + Tracer.delay(); + // } } // Update low value of 'u' only of 'v' is still in stack // (i.e. it's a back edge, not cross edge). else if (stackMember[v] === true) { low[u] = Math.min(low[u], disc[v]); + // visualize { lowTracer.patch(u, low[u]); Tracer.delay(); + // } } } } @@ -85,28 +102,36 @@ function SCCVertex(u, disc, low, st, stackMember, carry) { if (low[u] === disc[u]) { while (st[st.length - 1] !== u) { w = st.pop(); + // visualize { stTracer.set(st); Tracer.delay(); logger.println(w); Tracer.delay(); + // } stackMember[w] = false; + // visualize { stackMemberTracer.patch(w, false); Tracer.delay(); + // } } w = st.pop(); + // visualize { stTracer.set(st); Tracer.delay(); logger.println(w); Tracer.delay(); logger.println('------'); + // } stackMember[w] = false; + // visualize { stackMemberTracer.patch(w, false); Tracer.delay(); + // } } } diff --git a/Divide and Conquer/Merge Sort/bottomUp.js b/Divide and Conquer/Merge Sort/bottomUp.js index 195e8f47..e3200fed 100644 --- a/Divide and Conquer/Merge Sort/bottomUp.js +++ b/Divide and Conquer/Merge Sort/bottomUp.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -10,8 +13,11 @@ const D = [ tracer.set(D); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D[0].join(', ')}]`); +// } function mergeSort(start, end) { if (Math.abs(end - start) <= 1) return; @@ -21,7 +27,7 @@ function mergeSort(start, end) { let width; let i; for (width = 1; width < end; width *= 2) { - // visualization { + // visualize { logger.println(`merging arrays of width: ${width}`); // } for (i = 0; i < end; i += 2 * width) { @@ -34,7 +40,7 @@ function mergeSort(start, end) { mergeTo = 1 - mergeFrom; } if (mergeFrom !== 0) { - // visualization { + // visualize { logger.println('final copy to original'); // } copy(mergeFrom, mergeTo, start, end); @@ -47,7 +53,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { let k; // in an actual merge implementation, mergeFrom and mergeTo would be arrays // here for the ability to trace what is going on better, the arrays are D[mergeFrom] and D[mergeTo] - // visualization { + // visualize { logger.println(`merging segments [${start}..${middle}] and [${middle}..${end}]`); tracer.selectRow(mergeFrom, start, end - 1); Tracer.delay(); @@ -55,7 +61,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { // } for (k = start; k < end; k++) { - // visualization { + // visualize { if (j < end) { tracer.select(mergeFrom, j); } @@ -69,7 +75,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { // } if (i < middle && (j >= end || D[mergeFrom][i] <= D[mergeFrom][j])) { - // visualization { + // visualize { if (j < end) { logger.println('writing smaller value to output'); } else { @@ -84,7 +90,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { D[mergeTo][k] = D[mergeFrom][i]; i += 1; } else { - // visualization { + // visualize { if (i < middle) { logger.println('writing smaller value to output'); } else { @@ -105,7 +111,7 @@ function merge(mergeFrom, start, middle, end, mergeTo) { function copy(mergeFrom, mergeTo, start, end) { let i; for (i = start; i < end; i++) { - // visualization { + // visualize { tracer.select(mergeFrom, i); tracer.patch(mergeTo, i, D[mergeFrom][i]); Tracer.delay(); @@ -113,7 +119,7 @@ function copy(mergeFrom, mergeTo, start, end) { D[mergeTo][i] = D[mergeFrom][i]; - // visualization { + // visualize { tracer.deselect(mergeFrom, i); tracer.depatch(mergeTo, i); // } @@ -121,4 +127,6 @@ function copy(mergeFrom, mergeTo, start, end) { } mergeSort(0, D[0].length); +// logger { logger.println(`sorted array = [${D[0].join(', ')}]`); +// } diff --git a/Divide and Conquer/Merge Sort/topDown.js b/Divide and Conquer/Merge Sort/topDown.js index eac4f824..9ad9b208 100644 --- a/Divide and Conquer/Merge Sort/topDown.js +++ b/Divide and Conquer/Merge Sort/topDown.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } function mergeSort(start, end) { if (Math.abs(end - start) <= 1) return []; @@ -18,7 +24,9 @@ function mergeSort(start, end) { mergeSort(start, middle); mergeSort(middle, end); + // logger { logger.println(`divide left[${start}, ${middle - 1}], right[${middle}, ${end - 1}]`); + // } return mergeSort.merge(start, middle, end); } @@ -34,48 +42,68 @@ mergeSort.merge = (start, middle, end) => { for (i = 0; i < maxSize; i++) { if (i < leftSize) { left.push(D[start + i]); + // visualize { tracer.select(start + i); logger.println(`insert value into left array[${i}] = ${D[start + i]}`); Tracer.delay(); + // } } if (i < rightSize) { right.push(D[middle + i]); + // visualize { tracer.select(middle + i); logger.println(`insert value into right array[${i}] = ${D[middle + i]}`); Tracer.delay(); + // } } } + // logger { logger.println(`left array = [${left.join(', ')}], ` + `right array = [${right.join(', ')}]`); + // } i = 0; while (i < size) { if (left[0] && right[0]) { if (left[0] > right[0]) { D[start + i] = right.shift(); + // logger { logger.println(`rewrite from right array[${i}] = ${D[start + i]}`); + // } } else { D[start + i] = left.shift(); + // logger { logger.println(`rewrite from left array[${i}] = ${D[start + i]}`); + // } } } else if (left[0]) { D[start + i] = left.shift(); + // logger { logger.println(`rewrite from left array[${i}] = ${D[start + i]}`); + // } } else { D[start + i] = right.shift(); + // logger { logger.println(`rewrite from right array[${i}] = ${D[start + i]}`); + // } } + // visualize { tracer.deselect(start + i); tracer.patch(start + i, D[start + i]); Tracer.delay(); tracer.depatch(start + i); + // } i++; } const tempArray = []; for (i = start; i < end; i++) tempArray.push(D[i]); + // logger { logger.println(`merged array = [${tempArray.join(', ')}]`); + // } }; mergeSort(0, D.length); +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Divide and Conquer/Pigeonhole Sort/code.js b/Divide and Conquer/Pigeonhole Sort/code.js index 27923636..4617cdaf 100644 --- a/Divide and Conquer/Pigeonhole Sort/code.js +++ b/Divide and Conquer/Pigeonhole Sort/code.js @@ -1,14 +1,18 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const A = Randomize.Array1D({ N: 7 }); const N = A.length; +// define tracer variables { const tracer1 = new Array1DTracer('Array'); const tracer2 = new Array2DTracer('Holes'); const logTracer = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracer1, tracer2, logTracer])); tracer1.set(A); Tracer.delay(); +// } let min = A[0]; let max = A[0]; @@ -27,31 +31,47 @@ const holes = new Array(range); for (let i = 0; i < range; i++) { holes[i] = []; } +// visualize { tracer2.set(holes); +// } +// logger { logTracer.println('Filling up holes'); +// } for (let i = 0; i < N; i++) { + // visualize { tracer1.select(i); Tracer.delay(); + // } holes[A[i] - min].push(A[i]); + // visualize { tracer2.set(holes); tracer1.deselect(i); + // } } +// logger { logTracer.println('Building sorted array'); +// } let k = 0; for (let i = 0; i < range; i++) { for (let j = 0; j < holes[i].length; j++) { + // visualize { tracer2.select(i, j); Tracer.delay(); + // } A[k++] = holes[i][j]; + // visualize { tracer1.patch(k - 1, A[k - 1]); Tracer.delay(); tracer2.deselect(i, j); tracer1.depatch(k - 1); + // } } } +// logger { logTracer.println(`Sorted array is ${A}`); +// } diff --git a/Divide and Conquer/Quicksort/code.js b/Divide and Conquer/Quicksort/code.js index 0cd46345..4eb5373b 100644 --- a/Divide and Conquer/Quicksort/code.js +++ b/Divide and Conquer/Quicksort/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, ChartTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const chart = new ChartTracer(); const tracer = new Array1DTracer(); const logger = new LogTracer(); @@ -8,8 +11,11 @@ const D = Randomize.Array1D({ N: 15 }); tracer.set(D); tracer.chart(chart); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D.join(', ')}]`); +// } function partition(D, low, high) { let i; @@ -20,36 +26,48 @@ function partition(D, low, high) { j = high; s = D[low]; while (i < j) { + // visualize { tracer.select(high); tracer.select(low); Tracer.delay(); + // } while (D[j] > s) { + // visualize { tracer.select(j); Tracer.delay(); tracer.deselect(j); + // } j--; } D[i] = D[j]; + // visualize { tracer.patch(i, D[j]); Tracer.delay(); tracer.depatch(i); + // } while (s >= D[i] && i < j) { + // visualize { tracer.select(i); Tracer.delay(); tracer.deselect(i); + // } i++; } D[j] = D[i]; + // visualize { tracer.patch(j, D[i]); Tracer.delay(); tracer.depatch(j); tracer.deselect(high); tracer.deselect(low); + // } } D[i] = s; + // visualize { tracer.patch(i, s); Tracer.delay(); tracer.depatch(i); + // } partition(D, low, i - 1); low = i + 1; } @@ -60,4 +78,6 @@ function quicksort(D) { } quicksort(D); +// logger { logger.println(`sorted array = [${D.join(', ')}]`); +// } diff --git a/Divide and Conquer/Radix Sort/leastSignificantDigit.js b/Divide and Conquer/Radix Sort/leastSignificantDigit.js index 7a7c21d1..1d0d3ea6 100644 --- a/Divide and Conquer/Radix Sort/leastSignificantDigit.js +++ b/Divide and Conquer/Radix Sort/leastSignificantDigit.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -11,8 +14,11 @@ const D = [ ]; tracer.set(D); Tracer.delay(); +// } +// logger { logger.println(`original array = [${D[0].join(', ')}]`); +// } function pow(base, expo) { let ans = 1; @@ -27,55 +33,79 @@ function digit(i, exp) { } for (let exp = 0; exp < 3; exp++) { + // logger { logger.println(`Digit: ${exp}`); + // } let i; for (i = 0; i < D[0].length; i++) { const d = digit(i, exp); + // visualize { tracer.select(0, i); Tracer.delay(); + // } D[2][d] += 1; + // visualize { tracer.patch(2, d, D[2][d]); Tracer.delay(); tracer.depatch(2, d); tracer.deselect(0, i); + // } } for (i = 1; i < 10; i++) { + // visualize { tracer.select(2, i - 1); Tracer.delay(); + // } D[2][i] += D[2][i - 1]; + // visualize { tracer.patch(2, i, D[2][i]); Tracer.delay(); tracer.depatch(2, i); tracer.deselect(2, i - 1); + // } } for (i = D[0].length - 1; i >= 0; i--) { const d = digit(i, exp); + // visualize { tracer.select(0, i); Tracer.delay(); + // } D[2][d] -= 1; + // visualize { tracer.patch(2, d, D[2][d]); Tracer.delay(); tracer.depatch(2, d); + // } D[1][D[2][d]] = D[0][i]; + // visualize { tracer.patch(1, D[2][d], D[1][D[2][d]]); Tracer.delay(); tracer.depatch(1, D[2][d]); tracer.deselect(0, i); + // } } for (i = 0; i < D[0].length; i++) { + // visualize { tracer.select(1, i); Tracer.delay(); + // } D[0][i] = D[1][i]; + // visualize { tracer.patch(0, i, D[0][i]); Tracer.delay(); tracer.depatch(0, i); tracer.deselect(1, i); + // } } for (i = 0; i < 10; i++) { D[2][i] = 0; + // visualize { tracer.patch(2, i, D[2][i]); Tracer.delay(); tracer.depatch(2, i); + // } } } +// logger { logger.println(`sorted array = [${D[0].join(', ')}]`); +// } diff --git a/Dynamic Programming/Bellman-Ford's Shortest Path/code.js b/Dynamic Programming/Bellman-Ford's Shortest Path/code.js index 2bd0925c..69cae5bb 100644 --- a/Dynamic Programming/Bellman-Ford's Shortest Path/code.js +++ b/Dynamic Programming/Bellman-Ford's Shortest Path/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,6 +10,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: .5, value: () => Randomize.Integer({ min: -2, max: 5 }), weighted: true }); tracer.set(G); Tracer.delay(); +// } function BELLMAN_FORD(src, dest) { const weights = new Array(G.length); @@ -15,37 +19,51 @@ function BELLMAN_FORD(src, dest) { for (i = 0; i < G.length; i++) { weights[i] = MAX_VALUE; + // visualize { tracer.updateNode(i, weights[i]); + // } } weights[src] = 0; + // visualize { tracer.updateNode(src, 0); + // } + // logger { logger.println(`Initializing weights to: [${weights}]`); logger.println(''); + // } // begin BF algorithm execution let k = G.length; while (k--) { + // logger { logger.println(`Iteration: ${G.length - k}`); logger.println('------------------------------------------------------------------'); + // } for (i = 0; i < G.length; i++) { for (j = 0; j < G.length; j++) { if (G[i][j]) { // proceed to relax Edges only if a particular weight !== 0 (0 represents no edge) if (weights[j] > (weights[i] + G[i][j])) { weights[j] = weights[i] + G[i][j]; + // logger { logger.println(`weights[${j}] = weights[${i}] + ${G[i][j]}`); + // } } + // visualize { tracer.visit(j, i, weights[j]); Tracer.delay(); tracer.leave(j, i); Tracer.delay(); + // } } } } + // logger { logger.println(`updated weights: [${weights.join(', ')}]`); logger.println(''); + // } } // check for cycle @@ -54,14 +72,18 @@ function BELLMAN_FORD(src, dest) { for (j = 0; j < G.length; j++) { if (G[i][j]) { if (weights[j] > (weights[i] + G[i][j])) { + // logger { logger.println(`A cycle was detected: weights[${j}] > weights[${i}] + ${G[i][j]}`); + // } return (MAX_VALUE); } } } } + // logger { logger.println(`No cycles detected. Final weights for the source ${src} are: [${weights}]`); + // } return weights[dest]; } @@ -81,12 +103,16 @@ do { } while (src === dest); +// logger { logger.println(`finding the shortest path from ${src} to ${dest}`); +// } minWeight = BELLMAN_FORD(src, dest); +// logger { if (minWeight === MAX_VALUE) { logger.println(`there is no path from ${src} to ${dest}`); } else { logger.println(`the shortest path from ${src} to ${dest} is ${minWeight}`); } +// } diff --git a/Dynamic Programming/Catalan Number/code.js b/Dynamic Programming/Catalan Number/code.js index 74c520cd..f9b4830c 100644 --- a/Dynamic Programming/Catalan Number/code.js +++ b/Dynamic Programming/Catalan Number/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 10; const A = new Array(N + 1); @@ -6,24 +8,31 @@ for (let i = N; i >= 0; i--) { A[i] = 0; } +// define tracer variables { const tracer = new Array1DTracer(' Catalan Numbers '); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(A); Tracer.delay(); +// } A[0] = 1; +// visualize { tracer.patch(0, A[0]); Tracer.delay(); tracer.depatch(0); +// } A[1] = 1; +// visualize { tracer.patch(1, A[1]); Tracer.delay(); tracer.depatch(1); +// } for (let i = 2; i <= N; i++) { for (let j = 0; j < i; j++) { A[i] += A[j] * A[i - j - 1]; + // visualize { tracer.select(j); Tracer.delay(); tracer.select(i - j - 1); @@ -33,9 +42,12 @@ for (let i = 2; i <= N; i++) { tracer.deselect(j); tracer.deselect(i - j - 1); tracer.depatch(i); + // } } } +// visualize { logger.println(` The ${N}th Catalan Number is ${A[N]}`); tracer.select(N); Tracer.delay(); +// } diff --git a/Dynamic Programming/Fibonacci Sequence/code.js b/Dynamic Programming/Fibonacci Sequence/code.js index 66910bf6..3f10a27b 100644 --- a/Dynamic Programming/Fibonacci Sequence/code.js +++ b/Dynamic Programming/Fibonacci Sequence/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array1DTracer('Sequence'); Layout.setRoot(new VerticalLayout([tracer])); const index = 15; @@ -9,13 +12,16 @@ for (let i = 2; i < index; i++) { } tracer.set(D); Tracer.delay(); +// } for (let i = 2; i < index; i++) { D[i] = D[i - 2] + D[i - 1]; + // visualize { tracer.select(i - 2, i - 1); Tracer.delay(); tracer.patch(i, D[i]); Tracer.delay(); tracer.depatch(i); tracer.deselect(i - 2, i - 1); + // } } diff --git a/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js b/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js index 5c8dd7e7..e526c293 100644 --- a/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js +++ b/Dynamic Programming/Floyd-Warshall's Shortest Path/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,6 +10,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 5, ratio: 1, weighted: true }); tracer.set(G); Tracer.delay(); +// } function FloydWarshall() { // Finds the shortest path between all nodes @@ -27,32 +31,48 @@ function FloydWarshall() { for (let k = 0; k < G.length; k++) { for (let i = 0; i < G.length; i++) { if (k === i) continue; + // visualize { tracer.visit(k, i); Tracer.delay(); + // } for (let j = 0; j < G.length; j++) { if (i === j || j === k) continue; + // visualize { tracer.visit(j, k); Tracer.delay(); + // } if (S[i][j] > S[i][k] + S[k][j]) { + // visualize { tracer.visit(j, i, S[i][j]); Tracer.delay(); + // } S[i][j] = S[i][k] + S[k][j]; + // visualize { tracer.leave(j, i, S[i][j]); + // } } + // visualize { tracer.leave(j, k); + // } } + // visualize { tracer.leave(k, i); Tracer.delay(); + // } } } + // logger { for (let i = 0; i < G.length; i++) { for (let j = 0; j < G.length; j++) { if (S[i][j] === MAX_VALUE) logger.println(`there is no path from ${i} to ${j}`); else logger.println(`the shortest path from ${i} to ${j} is ${S[i][j]}`); } } + // } } let MAX_VALUE = Infinity; +// logger { logger.println('finding the shortest paths from and to all nodes'); +// } FloydWarshall(); diff --git a/Dynamic Programming/Integer Partition/code.js b/Dynamic Programming/Integer Partition/code.js index 0a4f969b..3618098c 100644 --- a/Dynamic Programming/Integer Partition/code.js +++ b/Dynamic Programming/Integer Partition/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array2DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -14,9 +17,12 @@ for (let i = 0; i <= integer; i++) { } tracer.set(D); Tracer.delay(); +// } function partition(A, n, p) { + // logger { if (n === 0) logger.println(`[${A.join(', ')}]`); + // } else { let end = n; if (p !== 0 && A[p - 1] < n) end = A[p - 1]; @@ -33,19 +39,27 @@ function integerPartition(n) { // We are allowed to use numbers from 2 to i for (let j = 1; j <= i; j++) { // Number of partitions without j number + number of partitions with max j + // visualize { tracer.select(i, j); Tracer.delay(); + // } D[i][j] = D[i][j - 1] + D[i - j][Math.max(j, i - j)]; + // visualize { tracer.patch(i, j, D[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.deselect(i, j); + // } } } return D[n][n]; } +// logger { logger.println(`Partitioning: ${integer}`); +// } partition(A, integer, 0); const part = integerPartition(integer); +// logger { logger.println(part); +// } diff --git a/Dynamic Programming/Knapsack Problem/code.js b/Dynamic Programming/Knapsack Problem/code.js index 83c5c567..8fc41c73 100644 --- a/Dynamic Programming/Knapsack Problem/code.js +++ b/Dynamic Programming/Knapsack Problem/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const val = [1, 4, 5, 7]; // The value of all available items const wt = [1, 3, 4, 5]; // The weights of available items @@ -13,6 +15,7 @@ for (let i = 0; i < N + 1; i++) { } } +// define tracer variables { const tracer = new Array2DTracer('Knapsack Table'); const dataViewer1 = new Array1DTracer('Values'); const dataViewer2 = new Array1DTracer('Weights'); @@ -22,6 +25,7 @@ tracer.set(DP); dataViewer1.set(val); dataViewer2.set(wt); Tracer.delay(); +// } for (let i = 0; i <= N; i++) { for (let j = 0; j <= W; j++) { @@ -31,16 +35,20 @@ for (let i = 0; i <= N; i++) { then the total weight in our collection is 0 */ DP[i][0] = 0; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); tracer.depatch(i, j); + // } } else if (wt[i - 1] <= j) { // take the current item in our collection + // visualize { dataViewer1.select(i - 1); Tracer.delay(); dataViewer2.select(i - 1); Tracer.delay(); tracer.select(i - 1, j); Tracer.delay(); + // } const A = val[i - 1] + DP[i - 1][j - wt[i - 1]]; const B = DP[i - 1][j]; @@ -50,25 +58,35 @@ for (let i = 0; i <= N; i++) { */ if (A > B) { DP[i][j] = A; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); + // } } else { DP[i][j] = B; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); + // } } + // visualize { tracer.deselect(i - 1, j); tracer.depatch(i, j); dataViewer2.deselect(i - 1); dataViewer1.deselect(i - 1); + // } } else { // leave the current item from our collection DP[i][j] = DP[i - 1][j]; + // visualize { tracer.patch(i, j, DP[i][j]); Tracer.delay(); tracer.depatch(i, j); + // } } } } +// logger { logger.println(` Best value we can achieve is ${DP[N][W]}`); +// } diff --git a/Dynamic Programming/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 cfc13fc0..1cc46e40 100644 --- a/Dynamic Programming/Longest Increasing Subsequence/code.js +++ b/Dynamic Programming/Longest Increasing Subsequence/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -7,35 +10,50 @@ const A = Randomize.Array1D({ N: 10, value: () => Randomize.Integer({ min: 0, ma const LIS = new Array(A.length); tracer.set(A); Tracer.delay(); +// } // Initialize LIS values for all indexes for (let i = 0; i < A.length; i++) { LIS[i] = 1; } +// logger { logger.println('Calculating Longest Increasing Subsequence values in bottom up manner '); +// } // Compute optimized LIS values in bottom up manner for (let i = 1; i < A.length; i++) { + // visualize { tracer.select(i); logger.println(` LIS[${i}] = ${LIS[i]}`); + // } for (let j = 0; j < i; j++) { + // visualize { tracer.patch(j); Tracer.delay(); tracer.depatch(j); + // } if (A[i] > A[j] && LIS[i] < LIS[j] + 1) { LIS[i] = LIS[j] + 1; + // logger { logger.println(` LIS[${i}] = ${LIS[i]}`); + // } } } + // visualize { tracer.deselect(i); + // } } // Pick maximum of all LIS values +// logger { logger.println('Now calculate maximum of all LIS values '); +// } let max = LIS[0]; for (let i = 1; i < A.length; i++) { if (max < LIS[i]) { max = LIS[i]; } } +// logger { logger.println(`Longest Increasing Subsequence = max of all LIS = ${max}`); +// } diff --git a/Dynamic Programming/Longest Palindromic Subsequence/code.js b/Dynamic Programming/Longest Palindromic Subsequence/code.js index 42b67224..1e7de776 100644 --- a/Dynamic Programming/Longest Palindromic Subsequence/code.js +++ b/Dynamic Programming/Longest Palindromic Subsequence/code.js @@ -1,9 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); - -const tracer = new Array1DTracer('Input Text'); -const matrix = new Array2DTracer('Matrix'); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, matrix, logger])); +// } const seq = 'BBABCBCAB'; let N; @@ -20,9 +17,15 @@ for (i = 0; i < N; i++) { L[i][i] = 1; } +// define tracer variables { +const tracer = new Array1DTracer('Input Text'); +const matrix = new Array2DTracer('Matrix'); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, matrix, logger])); tracer.set(seq); matrix.set(L); Tracer.delay(); +// } function max(a, b) { if (a > b) { @@ -31,56 +34,81 @@ function max(a, b) { return b; } +// logger { logger.println('LPS for any string with length = 1 is 1'); +// } for (i = 2; i <= N; i++) { + // logger { logger.println('--------------------------------------------------'); logger.println(`Considering a sub-string of length ${i}`); logger.println('--------------------------------------------------'); + // } for (j = 0; j < N - i + 1; j++) { const k = j + i - 1; + // visualize { tracer.select(j); Tracer.delay(); tracer.patch(k); Tracer.delay(); + // } + // logger { logger.println(`Comparing ${seq[j]} and ${seq[k]}`); + // } if (seq[j] === seq[k] && i === 2) { + // logger { logger.println(`They are equal and size of the string in the interval${j} to ${k} is 2, so the Longest Palindromic Subsequence in the Given range is 2`); + // } + // visualize { matrix.patch(j, k); Tracer.delay(); + // } L[j][k] = 2; + // visualize { matrix.set(L); matrix.depatch(j, k); Tracer.delay(); + // } } else if (seq[j] === seq[k]) { + // logger { logger.println(`They are equal, so the Longest Palindromic Subsequence in the Given range is 2 + the Longest Increasing Subsequence between the indices ${j + 1} to ${k - 1}`); + // } + // visualize { matrix.patch(j, k); Tracer.delay(); matrix.select(j + 1, k - 1); Tracer.delay(); + // } L[j][k] = L[j + 1][k - 1] + 2; + // visualize { matrix.set(L); matrix.depatch(j, k); Tracer.delay(); matrix.deselect(j + 1, k - 1); Tracer.delay(); + // } } else { + // logger { logger.println(`They are NOT equal, so the Longest Palindromic Subsequence in the Given range is the maximum Longest Increasing Subsequence between the indices ${j + 1} to ${k} and ${j} to ${k - 1}`); + // } + // visualize { matrix.patch(j, k); Tracer.delay(); matrix.select(j + 1, k); Tracer.delay(); matrix.select(j, k - 1); Tracer.delay(); + // } L[j][k] = max(L[j + 1][k], L[j][k - 1]); + // visualize { matrix.set(L); matrix.depatch(j, k); @@ -89,12 +117,19 @@ for (i = 2; i <= N; i++) { Tracer.delay(); matrix.deselect(j, k - 1); Tracer.delay(); + // } } + // logger { logger.println('--------------------------------------------------'); + // } + // visualize { tracer.deselect(j); Tracer.delay(); tracer.depatch(k); Tracer.delay(); + // } } } +// logger { logger.println(`Longest Increasing Subsequence of the given string = L[0][${N - 1}]=${L[0][N - 1]}`); +// } diff --git a/Dynamic Programming/Maximum Subarray/code.js b/Dynamic Programming/Maximum Subarray/code.js index 23bf888f..241f206c 100644 --- a/Dynamic Programming/Maximum Subarray/code.js +++ b/Dynamic Programming/Maximum Subarray/code.js @@ -1,39 +1,60 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +const D = [-2, -3, 4, -1, -2, 1, 5, -3]; + +// define tracer variables { const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); -const D = [-2, -3, 4, -1, -2, 1, 5, -3]; tracer.set(D); Tracer.delay(); +// } const maxSubarraySum = (function maxSubarray(array) { let maxSoFar = 0; let maxEndingHere = 0; + // logger { logger.println('Initializing maxSoFar = 0 & maxEndingHere = 0'); + // } for (let i = 0; i < array.length; i++) { + // visualize { tracer.select(i); + // } + // logger { logger.println(`${maxEndingHere} + ${array[i]}`); + // } maxEndingHere += array[i]; + // logger { logger.println(`=> ${maxEndingHere}`); + // } if (maxEndingHere < 0) { + // logger { logger.println('maxEndingHere is negative, set to 0'); + // } maxEndingHere = 0; } if (maxSoFar < maxEndingHere) { + // logger { logger.println(`maxSoFar < maxEndingHere, setting maxSoFar to maxEndingHere (${maxEndingHere})`); + // } maxSoFar = maxEndingHere; } + // visualize { Tracer.delay(); tracer.deselect(i); + // } } return maxSoFar; }(D)); +// logger { logger.println(`Maximum Subarray's Sum is: ${maxSubarraySum}`); +// } diff --git a/Dynamic Programming/Maximum Sum Path/code.js b/Dynamic Programming/Maximum Sum Path/code.js index 6a267ae1..b95e518e 100644 --- a/Dynamic Programming/Maximum Sum Path/code.js +++ b/Dynamic Programming/Maximum Sum Path/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const D = Randomize.Array2D({ N: 5, M: 5, value: () => Randomize.Integer({ min: 1, max: 5 }) }); const dataViewer = new Array2DTracer(); const tracer = new Array2DTracer('Results Table'); @@ -15,18 +18,21 @@ for (let i = 0; i < D.length; i++) { } tracer.set(DP); Tracer.delay(); +// } const N = DP.length; const M = DP[0].length; function update(i, j, value) { DP[i][j] = value; + // visualize { dataViewer.select(i, j); Tracer.delay(); tracer.patch(i, j, DP[i][j]); Tracer.delay(); tracer.depatch(i, j); dataViewer.deselect(i, j); + // } } for (let i = 0; i < N; i++) { @@ -34,20 +40,34 @@ for (let i = 0; i < N; i++) { if (i === 0 && j === 0) { update(i, j, D[i][j]); } else if (i === 0) { + // visualize { tracer.select(i, j - 1); + // } update(i, j, DP[i][j - 1] + D[i][j]); + // visualize { tracer.deselect(i, j - 1); + // } } else if (j === 0) { + // visualize { tracer.select(i - 1, j); + // } update(i, j, DP[i - 1][j] + D[i][j]); + // visualize { tracer.deselect(i - 1, j); + // } } else { + // visualize { tracer.select(i, j - 1); tracer.select(i - 1, j); + // } update(i, j, Math.max(DP[i][j - 1], DP[i - 1][j]) + D[i][j]); + // visualize { tracer.deselect(i, j - 1); tracer.deselect(i - 1, j); + // } } } } +// logger { logger.println(`max = ${DP[N - 1][M - 1]}`); +// } diff --git a/Dynamic Programming/Pascal's Triangle/code.js b/Dynamic Programming/Pascal's Triangle/code.js index b2e89291..eea8fd7c 100644 --- a/Dynamic Programming/Pascal's Triangle/code.js +++ b/Dynamic Programming/Pascal's Triangle/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 9; const A = new Array(N); @@ -6,32 +8,40 @@ for (let i = N - 1; i >= 0; i--) { A[i] = new Array(N); } +// define tracer variables { const tracer = new Array2DTracer('Pascal\'s Triangle'); Layout.setRoot(new VerticalLayout([tracer])); tracer.set(A); Tracer.delay(); +// } for (let i = 0; i < N; i++) { for (let j = 0; j <= i; j++) { if (j === i || j === 0) { // First and last values in every row are 1 A[i][j] = 1; + // visualize { tracer.patch(i, j, A[i][j]); Tracer.delay(); tracer.depatch(i, j); + // } } else { // Other values are sum of values just above and left of above + // visualize { tracer.select(i - 1, j - 1); Tracer.delay(); tracer.select(i - 1, j); Tracer.delay(); + // } A[i][j] = A[i - 1][j - 1] + A[i - 1][j]; + // visualize { tracer.patch(i, j, A[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.deselect(i - 1, j - 1); tracer.deselect(i - 1, j); + // } } } } diff --git a/Dynamic Programming/Shortest Common Supersequence/code.js b/Dynamic Programming/Shortest Common Supersequence/code.js index d60387c9..7c726fc3 100644 --- a/Dynamic Programming/Shortest Common Supersequence/code.js +++ b/Dynamic Programming/Shortest Common Supersequence/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const string1 = 'AGGTAB'; const string2 = 'GXTXAYB'; @@ -9,6 +11,7 @@ for (let i = 0; i < m + 1; i++) { A[i] = new Array(n + 1); } +// define tracer variables { const tracer1 = new Array1DTracer('String 1'); const tracer2 = new Array1DTracer('String 2'); const tracer3 = new Array2DTracer('Memo Table'); @@ -18,6 +21,7 @@ tracer1.set(string1); tracer2.set(string2); tracer3.set(A); Tracer.delay(); +// } let i; let j; @@ -30,23 +34,29 @@ for (i = 0; i <= m; i++) { } else if (j === 0) { A[i][j] = i; } else if (string1[i - 1] === string2[j - 1]) { + // visualize { tracer1.select(i - 1); Tracer.delay(); tracer2.select(j - 1); Tracer.delay(); tracer3.select(i - 1, j - 1); Tracer.delay(); + // } A[i][j] = A[i - 1][j - 1] + 1; + // visualize { tracer1.deselect(i - 1); tracer2.deselect(j - 1); tracer3.deselect(i - 1, j - 1); + // } } else { + // visualize { tracer3.select(i - 1, j); Tracer.delay(); tracer3.select(i, j - 1); Tracer.delay(); + // } if (A[i - 1][j] < A[i][j - 1]) { A[i][j] = 1 + A[i - 1][j]; @@ -54,13 +64,19 @@ for (i = 0; i <= m; i++) { A[i][j] = 1 + A[i][j - 1]; } + // visualize { tracer3.deselect(i - 1, j); tracer3.deselect(i, j - 1); + // } } + // visualize { tracer3.patch(i, j, A[i][j]); Tracer.delay(); tracer3.depatch(i, j); + // } } } +// logger { logger.println(`Shortest Common Supersequence is ${A[m][n]}`); +// } diff --git a/Dynamic Programming/Sieve of Eratosthenes/code.js b/Dynamic Programming/Sieve of Eratosthenes/code.js index 986a1192..fdac4920 100644 --- a/Dynamic Programming/Sieve of Eratosthenes/code.js +++ b/Dynamic Programming/Sieve of Eratosthenes/code.js @@ -1,6 +1,7 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array1DTracer('Sieve'); const N = 30; const a = []; const b = []; @@ -8,27 +9,41 @@ for (let i = 1; i <= N; i++) { a.push(i); b.push(0); } + +// define tracer variables { +const tracer = new Array1DTracer('Sieve'); tracer.set(a); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); Tracer.delay(); +// } +// visualize { logger.println('1 is not prime'); tracer.select(0); Tracer.delay(); +// } for (let i = 2; i <= N; i++) { if (b[i] === 0) { + // visualize { logger.println(`${i} is not marked, so it is prime`); // a[i-1] is prime mark by red indicators tracer.patch(i - 1); Tracer.delay(); + // } for (let j = i + i; j <= N; j += i) { b[j] = 1; // a[j-1] is not prime, mark by blue indicators + // visualize { logger.println(`${j} is a multiple of ${i} so it is marked as composite`); tracer.select(j - 1); Tracer.delay(); + // } } + // visualize { tracer.depatch(i - 1); + // } } } +// logger { logger.println(`The unmarked numbers are the prime numbers from 1 to ${N}`); +// } diff --git a/Dynamic Programming/Sliding Window/code.js b/Dynamic Programming/Sliding Window/code.js index 60d7212c..7cf9b4ad 100644 --- a/Dynamic Programming/Sliding Window/code.js +++ b/Dynamic Programming/Sliding Window/code.js @@ -1,24 +1,34 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); const D = Randomize.Array1D({ N: 20, value: () => Randomize.Integer({ min: -5, max: 5 }) }); tracer.set(D); Tracer.delay(); +// } let sum = D[0] + D[1] + D[2]; let max = sum; +// visualize { tracer.select(0, 2); logger.println(`sum = ${sum}`); Tracer.delay(); +// } for (let i = 3; i < D.length; i++) { sum += D[i] - D[i - 3]; if (max < sum) max = sum; + // visualize { tracer.deselect(i - 3); tracer.select(i); logger.println(`sum = ${sum}`); Tracer.delay(); + // } } +// visualize { tracer.deselect(D.length - 3, D.length - 1); logger.println(`max = ${max}`); +// } diff --git a/Dynamic Programming/Ugly Numbers/code.js b/Dynamic Programming/Ugly Numbers/code.js index 1f3006b5..356ab7de 100644 --- a/Dynamic Programming/Ugly Numbers/code.js +++ b/Dynamic Programming/Ugly Numbers/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const N = 15; const A = new Array(N); @@ -10,6 +12,7 @@ A[0] = 1; // By convention 1 is an ugly number const M = [2, 3, 5]; // multiples of 2, 3, 5 respectively const I = [0, 0, 0]; // iterators of 2, 3, 5 respectively +// define tracer variables { const tracer = new Array1DTracer('Ugly Numbers'); const tracer2 = new Array1DTracer('Multiples of 2, 3, 5'); const tracer3 = new Array1DTracer(' Iterators I0, I1, I2 '); @@ -19,45 +22,56 @@ tracer.set(A); tracer2.set(M); tracer3.set(I); Tracer.delay(); +// } for (let i = 1; i < N; i++) { // next is minimum of m2, m3 and m5 const next = (M[0] <= M[1]) ? (M[0] <= M[2]) ? M[0] : M[2] : (M[1] <= M[2]) ? M[1] : M[2]; + // logger { logger.println(` Minimum of ${M[0]}, ${M[1]}, ${M[2]} : ${next}`); + // } A[i] = next; + // visualize { tracer.patch(i, A[i]); Tracer.delay(); tracer.depatch(i); + // } if (next === M[0]) { I[0]++; M[0] = A[I[0]] * 2; + // visualize { tracer2.patch(0, M[0]); Tracer.delay(); tracer3.patch(0, I[0]); Tracer.delay(); tracer2.depatch(0); tracer3.depatch(0); + // } } if (next === M[1]) { I[1]++; M[1] = A[I[1]] * 3; + // visualize { tracer2.patch(1, M[1]); Tracer.delay(); tracer3.patch(1, I[1]); Tracer.delay(); tracer2.depatch(1); tracer3.depatch(1); + // } } if (next === M[2]) { I[2]++; M[2] = A[I[2]] * 5; + // visualize { tracer2.patch(2, M[2]); Tracer.delay(); tracer3.patch(2, I[2]); Tracer.delay(); tracer2.depatch(2); tracer3.depatch(2); + // } } } diff --git a/Dynamic Programming/Z String Search/code.js b/Dynamic Programming/Z String Search/code.js index b76cf622..cf831db3 100644 --- a/Dynamic Programming/Z String Search/code.js +++ b/Dynamic Programming/Z String Search/code.js @@ -1,9 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); - -const textTracer = new Array1DTracer('text'); -const pattTracer = new Array1DTracer('pattern'); -const concatTracer = new Array1DTracer('concatenated string'); -const tracer = new Array1DTracer('zArray'); +// } // let pattern = "aab"; // let text = "aabxaabxcaabxaabxay"; @@ -15,13 +12,18 @@ const len = pattern.length + text.length + 1; const z = new Array(len); z[0] = 0; +// define tracer variables { +const textTracer = new Array1DTracer('text'); +const pattTracer = new Array1DTracer('pattern'); +const concatTracer = new Array1DTracer('concatenated string'); +const tracer = new Array1DTracer('zArray'); pattTracer.set(pattern); textTracer.set(text); tracer.set(z); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([textTracer, pattTracer, concatTracer, tracer, logger])); Tracer.delay(); - +// } function createZarr(concat) { let left; @@ -31,19 +33,24 @@ function createZarr(concat) { left = 0; right = 0; for (let i = 1; i < N; i++) { + // visualize { tracer.select(i); Tracer.delay(); + // } if (i > right) { left = right = i; while (right < N && concat[right] === concat[right - left]) { + // visualize { concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is equal to ${concat[right - left]} (at index ${right - left})`); Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); + // } right++; } + // visualize { if (right < N) { concatTracer.patch(right); concatTracer.select(right - left); @@ -52,31 +59,43 @@ function createZarr(concat) { concatTracer.depatch(right); concatTracer.deselect(right - left); } + // } z[i] = (right - left); + // logger { logger.println('--------------------------------'); logger.println(`Value of z[${i}] = the length of the substring starting from ${i} which is also the prefix of the concatinated string(=${right - left})`); logger.println('--------------------------------'); + // } right--; } else if (z[i - left] < (right - i + 1)) { + // visualize { logger.println(`The substring from index ${i - left} will not cross the right end.`); concatTracer.patch(right - i + 1); concatTracer.select(i - left); Tracer.delay(); + // } z[i] = z[i - left]; + // visualize { concatTracer.depatch(right - i + 1); concatTracer.deselect(i - left); + // } } else { + // logger { logger.println(`The substring from index ${i - left} will cross the right end.`); + // } left = i; while (right < N && concat[right] === concat[right - left]) { + // visualize { concatTracer.patch(right); concatTracer.select(right - left); logger.println(`${concat[right]} (at index ${right}) is equal to ${concat[right - left]} (at index ${right - left})`); Tracer.delay(); concatTracer.depatch(right); concatTracer.deselect(right - left); + // } right++; } + // visualize { if (right < N) { concatTracer.patch(right); concatTracer.select(right - left); @@ -85,22 +104,32 @@ function createZarr(concat) { concatTracer.depatch(right); concatTracer.deselect(right - left); } + // } z[i] = (right - left); right--; + // logger { logger.println('--------------------------------'); logger.println(`Value of z[${i}] = the length of the substring starting from ${i} which is also the prefix of the concatinated string(=${right - left})`); logger.println('--------------------------------'); + // } } + // visualize { tracer.deselect(i); tracer.set(z); + // } } } const concat = `${pattern}$${text}`; +// visualize { concatTracer.set(concat); +// } const patLen = pattern.length; createZarr(concat); +// visualize { tracer.set(z); +// } +// logger { logger.println('The Values in Z array equal to the length of the pattern indicates the index at which the pattern is present'); logger.println('==================================='); for (let i = 0; i < len; i++) { @@ -110,3 +139,4 @@ for (let i = 0; i < len; i++) { } } logger.println('==================================='); +// } diff --git "a/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" "b/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" index bcd48952..be6b45af 100644 --- "a/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" +++ "b/Greedy/Boyer\342\200\223Moore's Majority Vote/code.js" @@ -1,79 +1,119 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const A = [1, 3, 3, 2, 1, 1, 1]; const N = A.length; +// define tracer variables { const tracer = new Array1DTracer('List of element'); const logger = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(A); Tracer.delay(); +// } function isMajorityElement(element) { let count = 0; + // logger { logger.println(`Verify majority element ${element}`); + // } for (let i = N - 1; i >= 0; i--) { + // visualize { tracer.patch(i, A[i]); Tracer.delay(); + // } if (A[i] === element) { count++; } else { + // visualize { tracer.depatch(i); + // } } } + // logger { logger.println(`Count of our assumed majority element ${count}`); + // } if (count > Math.floor(N / 2)) { + // logger { logger.println('Our assumption was correct!'); + // } return true; } + // logger { logger.println('Our assumption was incorrect!'); + // } return false; } function findProbableElement() { let index = 0; let count = 1; + // visualize { tracer.select(index); Tracer.delay(); + // } + // logger { logger.println(`Beginning with assumed majority element : ${A[index]} count : ${count}`); logger.println('--------------------------------------------------------'); + // } for (let i = 1; i < N; i++) { + // visualize { tracer.patch(i, A[i]); Tracer.delay(); + // } if (A[index] === A[i]) { count++; + // logger { logger.println(`Same as assumed majority element! Count : ${count}`); + // } } else { count--; + // logger { logger.println(`Not same as assumed majority element! Count : ${count}`); + // } } if (count === 0) { + // logger { logger.println('Wrong assumption in majority element'); + // } + // visualize { tracer.deselect(index); tracer.depatch(i); + // } index = i; count = 1; + // visualize { tracer.select(i); Tracer.delay(); + // } + // logger { logger.println(`New assumed majority element!${A[i]} Count : ${count}`); logger.println('--------------------------------------------------------'); + // } } else { + // visualize { tracer.depatch(i); + // } } } + // logger { logger.println(`Finally assumed majority element ${A[index]}`); logger.println('--------------------------------------------------------'); + // } return A[index]; } function findMajorityElement() { const element = findProbableElement(); + // logger { if (isMajorityElement(element) === true) { logger.println(`Majority element is ${element}`); } else { logger.println('No majority element'); } + // } } findMajorityElement(); diff --git a/Greedy/Dijkstra's Shortest Path/code.js b/Greedy/Dijkstra's Shortest Path/code.js index d0a57ad9..3cafa918 100644 --- a/Greedy/Dijkstra's Shortest Path/code.js +++ b/Greedy/Dijkstra's Shortest Path/code.js @@ -1,17 +1,22 @@ +// import visualization libraries { const { Tracer, Array1DTracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); +const MAX_VALUE = Infinity; +const S = []; // S[end] returns the distance from start node to end node +for (let i = 0; i < G.length; i++) S[i] = MAX_VALUE; + +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const tracerS = new Array1DTracer(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, tracerS, logger])); tracer.log(logger); -const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); -const MAX_VALUE = Infinity; -const S = []; // S[end] returns the distance from start node to end node -for (let i = 0; i < G.length; i++) S[i] = MAX_VALUE; tracerS.set(S); Tracer.delay(); +// } function Dijkstra(start, end) { let minIndex; @@ -19,10 +24,12 @@ function Dijkstra(start, end) { const D = []; // D[i] indicates whether the i-th node is discovered or not for (let i = 0; i < G.length; i++) D.push(false); S[start] = 0; // Starting node is at distance 0 from itself + // visualize { tracerS.patch(start, S[start]); Tracer.delay(); tracerS.depatch(start); tracerS.select(start); + // } let k = G.length; while (k--) { // Finding a node with the shortest distance from S[minIndex] @@ -35,30 +42,38 @@ function Dijkstra(start, end) { } if (minDistance === MAX_VALUE) break; // If there is no edge from current node, jump out of loop D[minIndex] = true; + // visualize { tracerS.select(minIndex); tracer.visit(minIndex); Tracer.delay(); + // } // For every unvisited neighbour of current node, we check // whether the path to it is shorter if going over the current node for (let i = 0; i < G.length; i++) { if (G[minIndex][i] && S[i] > S[minIndex] + G[minIndex][i]) { S[i] = S[minIndex] + G[minIndex][i]; + // visualize { tracerS.patch(i, S[i]); tracer.visit(i, minIndex, S[i]); Tracer.delay(); tracerS.depatch(i); tracer.leave(i, minIndex); Tracer.delay(); + // } } } + // visualize { tracer.leave(minIndex); Tracer.delay(); + // } } + // logger { if (S[end] === MAX_VALUE) { logger.println(`there is no path from ${start} to ${end}`); } else { logger.println(`the shortest path from ${start} to ${end} is ${S[end]}`); } + // } } const s = Randomize.Integer({ min: 0, max: G.length - 1 }); // s = start node @@ -66,6 +81,8 @@ let e; // e = end node do { e = Randomize.Integer({ min: 0, max: G.length - 1 }); } while (s === e); +// logger { logger.println(`finding the shortest path from ${s} to ${e}`); Tracer.delay(); +// } Dijkstra(s, e); diff --git a/Greedy/Job Scheduling Problem/code.js b/Greedy/Job Scheduling Problem/code.js index d8888165..4192792d 100644 --- a/Greedy/Job Scheduling Problem/code.js +++ b/Greedy/Job Scheduling Problem/code.js @@ -1,16 +1,11 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const jobId = ['a', 'b', 'c', 'd', 'e']; const deadline = [2, 1, 2, 1, 3]; const profit = [100, 19, 27, 25, 15]; const N = deadline.length; - -const tracer3 = new Array1DTracer('Schedule'); -const tracer = new Array1DTracer('Job Ids'); -const tracer1 = new Array1DTracer('Deadlines'); -const tracer2 = new Array1DTracer('Profit'); -Layout.setRoot(new VerticalLayout([tracer3, tracer, tracer1, tracer2])); - // sort according to decreasing order of profit // Bubble sort implemented ... Implement a better algorithm for better performance for (let i = 0; i < N - 1; i++) { @@ -34,11 +29,19 @@ const result = new Array(N); for (let i = N - 1; i >= 0; i--) { result[i] = '-'; } + +// define tracer variables { +const tracer3 = new Array1DTracer('Schedule'); +const tracer = new Array1DTracer('Job Ids'); +const tracer1 = new Array1DTracer('Deadlines'); +const tracer2 = new Array1DTracer('Profit'); +Layout.setRoot(new VerticalLayout([tracer3, tracer, tracer1, tracer2])); tracer.set(jobId); tracer1.set(deadline); tracer2.set(profit); tracer3.set(result); Tracer.delay(); +// } // Initialise all slots to free for (let i = 0; i < N; i++) { @@ -51,21 +54,29 @@ for (let i = 0; i < N; i++) { Start from the last possible slot. Find a slot for the job */ + // visualize { tracer.select(i); Tracer.delay(); tracer1.select(i); Tracer.delay(); + // } for (let j = Math.min(N, deadline[i]) - 1; j >= 0; j--) { if (slot[j] === 0) { + // visualize { tracer3.patch(j, jobId[i]); Tracer.delay(); + // } result[j] = jobId[i]; slot[j] = 1; + // visualize { tracer3.depatch(j); + // } break; } } + // visualize { tracer.deselect(i); tracer1.deselect(i); + // } } diff --git a/Greedy/Kruskal's Minimum Spanning Tree/code.js b/Greedy/Kruskal's Minimum Spanning Tree/code.js index 77b9ff6a..8cc2535e 100644 --- a/Greedy/Kruskal's Minimum Spanning Tree/code.js +++ b/Greedy/Kruskal's Minimum Spanning Tree/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -13,6 +16,7 @@ Layout.setRoot(new VerticalLayout([tracer, logger])); const G = Randomize.Graph({ N: 5, ratio: 1, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function kruskal() { const vcount = G.length; @@ -40,12 +44,16 @@ function kruskal() { let wsum = 0; for (let n = 0; n < vcount - 1 && edges.length > 0;) { const e = edges.shift(); // Get the edge of min weight + // visualize { tracer.visit(e[0], e[1]); Tracer.delay(); + // } if (t[e[0]] === t[e[1]]) { // e[0] & e[1] already in the same tree, ignore + // visualize { tracer.leave(e[0], e[1]); Tracer.delay(); + // } continue; } @@ -61,7 +69,9 @@ function kruskal() { n += 1; } + // logger { logger.println(`The sum of all edges is: ${wsum}`); + // } } kruskal(); diff --git a/Greedy/Prim's Minimum Spanning Tree/code.js b/Greedy/Prim's Minimum Spanning Tree/code.js index e44458fc..107f0144 100644 --- a/Greedy/Prim's Minimum Spanning Tree/code.js +++ b/Greedy/Prim's Minimum Spanning Tree/code.js @@ -1,5 +1,8 @@ +// import visualization libraries { const { Tracer, GraphTracer, LogTracer, Randomize, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const tracer = new GraphTracer().directed(false).weighted(); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); @@ -14,6 +17,7 @@ tracer.log(logger); const G = Randomize.Graph({ N: 10, ratio: .4, directed: false, weighted: true }); tracer.set(G); Tracer.delay(); +// } function prim() { // Finds a tree so that there exists a path between @@ -33,8 +37,10 @@ function prim() { { for (let j = 0; j < G.length; j++) { if (!D[j] && G[i][j]) { + // visualize { tracer.visit(i, j); Tracer.delay(); + // } // Second node must not be visited and must be connected to first node if (G[i][j] < minD) { // Searching for cheapest edge which satisfies requirements @@ -42,19 +48,27 @@ function prim() { minI = i; minJ = j; } + // visualize { tracer.leave(i, j); Tracer.delay(); + // } } } } } + // visualize { tracer.visit(minI, minJ); Tracer.delay(); + // } D[minJ] = 1; // Visit second node and insert it into or tree sum += G[minI][minJ]; } + // logger { logger.println(`The sum of all edges is: ${sum}`); + // } } +// logger { logger.println('nodes that belong to minimum spanning tree are: '); +// } prim(); diff --git a/Greedy/Stable Matching/code.js b/Greedy/Stable Matching/code.js index 1c15579e..40369cf2 100644 --- a/Greedy/Stable Matching/code.js +++ b/Greedy/Stable Matching/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const ARank = { Flavio: ['Valentine', 'July', 'Summer', 'Violet'], @@ -14,6 +16,7 @@ const BRank = { Summer: ['Stephen', 'Flavio', 'Albert', 'Jack'], }; +// define tracer variables { const tracerA = new Array1DTracer('A'); const tracerB = new Array1DTracer('B'); @@ -25,6 +28,7 @@ tracerB.set(_bKeys); const logTracer = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracerA, tracerB, logTracer])); Tracer.delay(); +// } function init(rank) { const o = {}; @@ -51,44 +55,58 @@ const B = init(BRank); let a; while ((a = extractUnstable(A))) { + // logger { logTracer.println(`Selecting ${a.key}`); Tracer.delay(); + // } const bKey = a.rankKeys.shift(); const b = B[bKey]; + // logger { logTracer.println(`--> Choicing ${b.key}`); Tracer.delay(); + // } if (b.stable === false) { + // logger { logTracer.println(`--> ${b.key} is not stable, stabilizing with ${a.key}`); Tracer.delay(); + // } a.stable = b; b.stable = a; + // visualize { tracerA.select(_aKeys.indexOf(a.key)); Tracer.delay(); tracerB.select(_bKeys.indexOf(b.key)); Tracer.delay(); + // } } else { const rankAinB = b.rankKeys.indexOf(a.key); const rankPrevAinB = b.rankKeys.indexOf(b.stable.key); if (rankAinB < rankPrevAinB) { + // logger { logTracer.println(`--> ${bKey} is more stable with ${a.key} rather than ${b.stable.key} - stabilizing again`); Tracer.delay(); + // } A[b.stable.key].stable = false; + // visualize { tracerA.deselect(_aKeys.indexOf(b.stable.key)); Tracer.delay(); + // } a.stable = b; b.stable = a; + // visualize { tracerA.select(_aKeys.indexOf(a.key)); Tracer.delay(); tracerB.select(_bKeys.indexOf(b.key)); Tracer.delay(); + // } } } } diff --git a/Simple Recursive/Cellular Automata/code.js b/Simple Recursive/Cellular Automata/code.js index c65f1954..58246d56 100644 --- a/Simple Recursive/Cellular Automata/code.js +++ b/Simple Recursive/Cellular Automata/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const gridSize = 10; const generations = 4; @@ -18,11 +20,15 @@ for (let i = 0; i < gridSize; i++) { nextG[i][j] = '#'; } } + +// define tracer variables { const tracer = new Array2DTracer(); Layout.setRoot(new VerticalLayout([tracer])); tracer.set(G); Tracer.delay(); +// } +// visualize { for (let gi = 0; gi < G.length; gi++) { for (let gj = 0; gj < G[gi].length; gj++) { if (G[gi][gj] === '#') { @@ -30,6 +36,7 @@ for (let gi = 0; gi < G.length; gi++) { } } } +// } function CellularAutomata(fillShape, emptyShape) { const nextGrid = []; @@ -70,10 +77,13 @@ function CellularAutomata(fillShape, emptyShape) { for (let i = 0; i < nextGrid.length; i++) { for (let j = 0; j < nextGrid[i].length; j++) { + // visualize { tracer.depatch(i, j, G[i][j]); tracer.select(i, j); Tracer.delay(); + // } G[i][j] = nextGrid[i][j]; + // visualize { if (G[i][j] === fillShape) { tracer.patch(i, j, G[i][j]); } else { @@ -81,6 +91,7 @@ function CellularAutomata(fillShape, emptyShape) { tracer.depatch(i, j, G[i][j]); tracer.deselect(i, j); } + // } } } } diff --git a/Simple Recursive/Euclidean Greatest Common Divisor/code.js b/Simple Recursive/Euclidean Greatest Common Divisor/code.js index 7f7dc53c..3419978f 100644 --- a/Simple Recursive/Euclidean Greatest Common Divisor/code.js +++ b/Simple Recursive/Euclidean Greatest Common Divisor/code.js @@ -1,42 +1,63 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array1DTracer('Euclidean Algorithm'); const a = []; a.push(465); a.push(255); + +// define tracer variables { +const tracer = new Array1DTracer('Euclidean Algorithm'); tracer.set(a); const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([tracer, logger])); Tracer.delay(); +// } +// logger { logger.println(`Finding the greatest common divisor of ${a[0]} and ${a[1]}`); logger.println('Checking if first number is at most the second number'); +// } if (a[0] > a[1]) { const tmp = a[0]; a[0] = a[1]; a[1] = tmp; + // logger { logger.println('The first number is bigger than the second number. Switching the numbers.'); + // } + // visualize { tracer.set(a); Tracer.delay(); + // } } while (a[0] > 0) { + // logger { logger.println(`${a[1]} % ${a[0]} = ${a[1] % a[0]}`); logger.println('Switching a[1] with a[1]%a[0]'); + // } a[1] %= a[0]; + // visualize { tracer.patch(1, a[1]); Tracer.delay(); + // } + // logger { logger.println('Now switching the two values to keep a[0] < a[1]'); + // } const tmp = a[0]; a[0] = a[1]; a[1] = tmp; + // visualize { tracer.patch(0, a[0]); tracer.patch(1, a[1]); Tracer.delay(); tracer.depatch(0); tracer.depatch(1); + // } } +// logger { logger.println(`The greatest common divisor is ${a[1]}`); +// } diff --git a/Simple Recursive/Suffix Array/code.js b/Simple Recursive/Suffix Array/code.js index 6ddf49b4..dc0c0261 100644 --- a/Simple Recursive/Suffix Array/code.js +++ b/Simple Recursive/Suffix Array/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } let word = 'virgo'; const suffixArray = (function skeleton(word) { @@ -11,6 +13,7 @@ const suffixArray = (function skeleton(word) { return arr; }(word)); +// define tracer variables { const saTracer = new Array2DTracer('Suffix Array'); const wordTracer = new Array1DTracer('Given Word'); const logger = new LogTracer('Progress'); @@ -19,24 +22,35 @@ Layout.setRoot(new VerticalLayout([saTracer, wordTracer, logger])); saTracer.set(suffixArray); wordTracer.set(word); Tracer.delay(); +// } word += '$'; // special character +// logger { logger.println('Appended \'$\' at the end of word as terminating (special) character. Beginning filling of suffixes'); +// } function selectSuffix(word, i) { let c = i; while (i < word.length - 1) { + // visualize { wordTracer.select(i); + // } i++; } + // visualize { Tracer.delay(); + // } while (c < word.length - 1) { + // visualize { wordTracer.deselect(c); + // } c++; } + // visualize { Tracer.delay(); + // } } (function createSA(sa, word) { @@ -44,19 +58,26 @@ function selectSuffix(word, i) { sa[i][1] = word.slice(i); selectSuffix(word, i); + // visualize { saTracer.patch(i, 1, sa[i][1]); Tracer.delay(); saTracer.depatch(i, 1); Tracer.delay(); + // } } }(suffixArray, word)); +// logger { logger.println('Re-organizing Suffix Array in sorted order of suffixes using efficient sorting algorithm (O(N.log(N)))'); +// } suffixArray.sort((a, b) => { + // logger { logger.println(`The condition a [1] (${a[1]}) > b [1] (${b[1]}) is ${a[1] > b[1]}`); + // } return a[1] > b[1]; }); +// visualize { for (let i = 0; i < word.length; i++) { saTracer.patch(i, 0, suffixArray[i][0]); saTracer.patch(i, 1, suffixArray[i][1]); @@ -65,3 +86,4 @@ for (let i = 0; i < word.length; i++) { saTracer.depatch(i, 0); saTracer.depatch(i, 1); } +// } diff --git a/Uncategorized/Affine Cipher/code.js b/Uncategorized/Affine Cipher/code.js index 934b6f6e..55bc0349 100644 --- a/Uncategorized/Affine Cipher/code.js +++ b/Uncategorized/Affine Cipher/code.js @@ -1,6 +1,10 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const plainText = 'secret'; + +// define tracer variables { const ptTracer = new Array1DTracer('Encryption'); const ctTracer = new Array1DTracer('Decryption'); const logger = new LogTracer(); @@ -8,6 +12,7 @@ Layout.setRoot(new VerticalLayout([ptTracer, ctTracer, logger])); ptTracer.set(plainText); Tracer.delay(); +// } /* code assumes that plainText contains ONLY LOWER CASE ALPHABETS @@ -27,26 +32,34 @@ function encrypt(plainText) { const index = alpha.charCodeAt(0) - 'a'.charCodeAt(0); let result = ((keys.a * index) + keys.b).mod(N); + // logger { logger.println(`Index of ${alpha} = ${index}`); + // } result += 'a'.charCodeAt(0); return String.fromCharCode(result); } + // logger { logger.println('Beginning Affine Encryption'); logger.println('Encryption formula: ((keys.a * indexOfAlphabet) + keys.b) % N'); logger.println(`keys.a=${keys.a}, keys.b=${keys.b}, N=${N}`); + // } for (const i in plainText) { + // visualize { ptTracer.select(i); Tracer.delay(); ptTracer.deselect(i); + // } cypherText += cryptAlpha(plainText[i]); + // visualize { ptTracer.patch(i, cypherText.slice(-1)); Tracer.delay(); ptTracer.depatch(i); + // } } return cypherText; @@ -62,34 +75,44 @@ function decrypt(cypherText) { } })()); + // logger { logger.println(`a-1 = ${aInverse}`); + // } function decryptAlpha(alpha) { const index = alpha.charCodeAt(0) - 'a'.charCodeAt(0); let result = (aInverse * (index - keys.b)).mod(N); + // logger { logger.println(`Index of ${alpha} = ${index}`); + // } result += 'a'.charCodeAt(0); return String.fromCharCode(result); } + // logger { logger.println('Beginning Affine Decryption'); logger.println('Decryption formula: (a-1 * (index - keys.b)) % N'); logger.println(`keys.b=${keys.b}, N=${N}`); + // } for (const i in cypherText) { + // visualize { ctTracer.select(i); Tracer.delay(); ctTracer.deselect(i); Tracer.delay(); + // } plainText += decryptAlpha(cypherText[i]); + // visualize { ctTracer.patch(i, plainText.slice(-1)); Tracer.delay(); ctTracer.depatch(i); Tracer.delay(); + // } } return plainText; diff --git a/Uncategorized/Caesar Cipher/code.js b/Uncategorized/Caesar Cipher/code.js index 4edf6f16..b2c60e09 100644 --- a/Uncategorized/Caesar Cipher/code.js +++ b/Uncategorized/Caesar Cipher/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array1DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const string = 'hello! how are you doing?'; const rotation = 5; @@ -11,6 +13,7 @@ const alphabetMap = alphabet.split('').reduce((map, curr, idx) => { return map; }, {}); +// define tracer variables { const encryptTracer = new Array1DTracer('Encryption'); const decryptTracer = new Array1DTracer('Decryption'); const logger = new LogTracer(); @@ -18,6 +21,7 @@ Layout.setRoot(new VerticalLayout([encryptTracer, decryptTracer, logger])); encryptTracer.set(string); Tracer.delay(); +// } function getPosUp(pos) { return (pos === alphabet.length - 1) ? 0 : pos + 1; @@ -32,7 +36,9 @@ function getNextChar(currChar, direction) { const nextPos = direction === 'up' ? getPosUp(pos) : getPosDown(pos); const nextChar = alphabet.charAt(nextPos); + // logger { logger.println(`${currChar} -> ${nextChar}`); + // } return nextChar; } @@ -40,45 +46,65 @@ function cipher(str, rotation, direction, cipherTracer) { if (!str) return ''; for (let i = 0; i < str.length; i++) { + // visualize { Tracer.delay(); + // } let currChar = str.charAt(i); if (typeof alphabetMap[currChar] === 'number') { // don't encrpt/decrypt characters not in alphabetMap let r = rotation; + // logger { logger.println(`Rotating ${currChar} ${direction} ${rotation} times`); + // } + // visualize { cipherTracer.select(i); Tracer.delay(); + // } // perform given amount of rotations in the given direction while (r-- > 0) { currChar = getNextChar(currChar, direction); + // visualize { cipherTracer.patch(i, currChar); Tracer.delay(); + // } } } else { + // logger { logger.println('Ignore this character'); + // } } str = str.substring(0, i) + currChar + str.substring(i + 1); + // logger { logger.println(`Current result: ${str}`); + // } } return str; } function encrypt(str, rotation) { + // logger { logger.println(`Encrypting: ${str}`); + // } return cipher(str, rotation, 'up', encryptTracer); } function decrypt(str, rotation) { + // logger { logger.println(`Decrypting: ${str}`); + // } return cipher(str, rotation, 'down', decryptTracer); } const encrypted = encrypt(string, rotation); +// logger { logger.println(`Encrypted result: ${encrypted}`); +// } decryptTracer.set(encrypted); const decrypted = decrypt(encrypted, rotation); +// logger { logger.println(`Decrypted result: ${decrypted}`); +// } diff --git a/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js b/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js index b2afff6c..86fce896 100644 --- a/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js +++ b/Uncategorized/Freivalds' Matrix-Multiplication Verification/code.js @@ -1,9 +1,12 @@ +// import visualization libraries { const { Tracer, Array1DTracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const A = [[2, 3], [3, 4]]; const B = [[1, 0], [1, 2]]; const C = [[6, 5], [8, 7]]; +// define tracer variables { const matrixATracer = new Array2DTracer('Matrix A'); const matrixBTracer = new Array2DTracer('Matrix B'); const matrixCTracer = new Array2DTracer('Matrix C'); @@ -15,6 +18,7 @@ matrixATracer.set(A); matrixBTracer.set(B); matrixCTracer.set(C); Tracer.delay(); +// } function FreivaldsAlgorithm() { let k = 5; @@ -26,7 +30,9 @@ function FreivaldsAlgorithm() { const n = A.length; while (k--) { + // logger { logger.println(`Iterations remained: #${k}`); + // } // Generate random vector const r = []; @@ -36,8 +42,10 @@ function FreivaldsAlgorithm() { P.push(-1); r.push((Math.random() < 0.5) << 0); } + // visualize { randomVectorTracer.set(r); Tracer.delay(); + // } // Compute Br, Cr const Br = []; @@ -63,17 +71,23 @@ function FreivaldsAlgorithm() { } P.push(tmp); } + // visualize { resultVectorTracer.set(P); Tracer.delay(); + // } for (i = 0; i < n; i++) { if (P[i] !== 0) { + // logger { logger.println(`P[${i}] !== 0 (${P[i]}), exit`); + // } return false; } } + // logger { logger.println('Result vector is identity, continue...'); + // } } return true; diff --git a/Uncategorized/Magic Square/code.js b/Uncategorized/Magic Square/code.js index 88f62f5c..912f52d9 100644 --- a/Uncategorized/Magic Square/code.js +++ b/Uncategorized/Magic Square/code.js @@ -1,4 +1,6 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } const n = 7; const A = new Array(n); @@ -12,51 +14,67 @@ for (let i = n - 1; i >= 0; i--) { } } +// define tracer variables { const tracer = new Array2DTracer('Magic Square'); const logTracer = new LogTracer('Console'); Layout.setRoot(new VerticalLayout([tracer, logTracer])); tracer.set(A); Tracer.delay(); +// } let i = Math.floor(n / 2); let j = n - 1; for (let num = 1; num <= n * n;) { + // logger { logTracer.println(`i = ${i}`); logTracer.println(`j = ${j}`); + // } if (i === -1 && j === n) { j = n - 2; i = 0; + // logger { logTracer.println('Changing : '); logTracer.println(`i = ${i}`); logTracer.println(`j = ${j}`); + // } } else { if (j === n) { j = 0; + // logger { logTracer.println(`Changing : j = ${j}`); + // } } if (i < 0) { i = n - 1; + // logger { logTracer.println(`Changing : i = ${i}`); + // } } } if (A[i][j] > 0) { + // logger { logTracer.println(`Cell already filled : Changing i = ${i} j = ${j}`); + // } j -= 2; i++; } else { A[i][j] = num++; + // visualize { tracer.patch(i, j, A[i][j]); Tracer.delay(); tracer.depatch(i, j); tracer.select(i, j); Tracer.delay(); + // } j++; i--; } } +// logger { logTracer.println(`Magic Constant is ${n * (n * n + 1) / 2}`); +// } diff --git a/Uncategorized/Maze Generation/code.js b/Uncategorized/Maze Generation/code.js index 835c62b1..223753ef 100644 --- a/Uncategorized/Maze Generation/code.js +++ b/Uncategorized/Maze Generation/code.js @@ -1,8 +1,7 @@ +// import visualization libraries { const { Tracer, Array2DTracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } -const tracer = new Array2DTracer(); -const logger = new LogTracer(); -Layout.setRoot(new VerticalLayout([tracer, logger])); const n = 6; // rows (change these!) const m = 6; // columns (change these!) @@ -56,8 +55,13 @@ for (let i = 0; i < vEnd; i++) { // by row } } +// define tracer variables { +const tracer = new Array2DTracer(); +const logger = new LogTracer(); +Layout.setRoot(new VerticalLayout([tracer, logger])); tracer.set(G); Tracer.delay(); +// } function buildMaze() { const mySet = new disjointSet(); @@ -73,7 +77,9 @@ function buildMaze() { mySet.addElements(width * height); + // logger { logger.println('initializing grid (all walls are up)'); + // } // init 'graph' // each room has two walls, a down and right wall. for (let i = 0; i < width; i++) { @@ -91,7 +97,9 @@ function buildMaze() { G[j * 2 + 1][i * 3 + 1] = locationString[0]; G[j * 2 + 1][i * 3 + 2] = locationString[1]; + // visualize { tracer.set(G); + // } } rightWalls.push({ x: i, y: j }); @@ -100,7 +108,9 @@ function buildMaze() { } } + // logger { logger.println('shuffled the walls for random selection'); + // } // Randomly shuffle the walls shuffle(rightWalls); shuffle(downWalls); @@ -117,26 +127,34 @@ function buildMaze() { if (iYdown < height) { const u = graph[iX][iY]; const v = graph[iX][iYdown]; + // visualize { tracer.patch(iY * 2 + 1, iX * 3 + 1); tracer.patch(iY * 2 + 1, iX * 3 + 2); tracer.patch(iYdown * 2 + 1, iX * 3 + 1); tracer.patch(iYdown * 2 + 1, iX * 3 + 2); + // } if (mySet.find(u) !== mySet.find(v)) { + // logger { logger.println(`Rooms: ${u} & ${v} now belong to the same set, delete wall between them`); Tracer.delay(); + // } mySet.setUnion(u, v); setSize++; // delete wall walls[u].down = false; } else { + // logger { logger.println(`Rooms: ${u} & ${v} would create a cycle! This is not good!`); Tracer.delay(); + // } } + // visualize { tracer.depatch(iY * 2 + 1, iX * 3 + 1); tracer.depatch(iY * 2 + 1, iX * 3 + 2); tracer.depatch(iYdown * 2 + 1, iX * 3 + 1); tracer.depatch(iYdown * 2 + 1, iX * 3 + 2); + // } } } else if (randomWall === 2 && rightWalls.length > 0) { // Right Wall @@ -147,31 +165,41 @@ function buildMaze() { if (iXright < width) { const u = graph[iX][iY]; const v = graph[iXright][iY]; + // visualize { tracer.patch(iY * 2 + 1, iX * 3 + 1); tracer.patch(iY * 2 + 1, iX * 3 + 2); tracer.patch(iY * 2 + 1, iXright * 3 + 1); tracer.patch(iY * 2 + 1, iXright * 3 + 2); + // } if (mySet.find(u) !== mySet.find(v)) { + // logger { logger.println(`Rooms: ${u} & ${v} now belong to the same set, delete wall between them`); Tracer.delay(); + // } mySet.setUnion(u, v); setSize++; // delete wall walls[u].right = false; } else { + // logger { logger.println(`Rooms: ${u} & ${v} would create a cycle! This is not good!`); Tracer.delay(); + // } } + // visualize { tracer.depatch(iY * 2 + 1, iX * 3 + 1); tracer.depatch(iY * 2 + 1, iX * 3 + 2); tracer.depatch(iY * 2 + 1, iXright * 3 + 1); tracer.depatch(iY * 2 + 1, iXright * 3 + 2); + // } } } } + // logger { logger.println('deleting the walls'); + // } // update deleted walls for (let i = 0; i < width; i++) { for (let j = 0; j < height; j++) { @@ -180,28 +208,38 @@ function buildMaze() { if (currentWall.down === false) { G[j * 2 + 2][i * 3 + 1] = ' '; G[j * 2 + 2][i * 3 + 2] = ' '; + // visualize { tracer.select(j * 2 + 2, i * 3 + 1); Tracer.delay(); tracer.select(j * 2 + 2, i * 3 + 2); Tracer.delay(); + // } } if (currentWall.right === false) { G[j * 2 + 1][i * 3 + 3] = ' '; + // visualize { tracer.select(j * 2 + 1, i * 3 + 3); Tracer.delay(); + // } } + // visualize { tracer.set(G); + // } } } + // logger { logger.println('cleaning up the grid!'); + // } cleanUpGrid(width, height); // Clear out walls for the start and end locations. const randomStart = Math.floor(Math.random() * width); const randomEnd = Math.floor(Math.random() * width); + // logger { logger.println('setting the Start (S) & End (E) locations'); + // } // Start Location G[0][randomStart * 3 + 1] = ' '; @@ -216,10 +254,14 @@ function buildMaze() { cleanUpStartLocation(randomStart); cleanUpEndLocation(randomEnd); + // logger { logger.println('maze is completed!'); + // } // set the data + // visualize { tracer.set(G); + // } } function cleanUpStartLocation(start) { diff --git a/Uncategorized/Miller-Rabin's Primality Test/code.js b/Uncategorized/Miller-Rabin's Primality Test/code.js index 91eec368..50a374e9 100644 --- a/Uncategorized/Miller-Rabin's Primality Test/code.js +++ b/Uncategorized/Miller-Rabin's Primality Test/code.js @@ -1,18 +1,26 @@ +// import visualization libraries { const { Tracer, LogTracer, Layout, VerticalLayout } = require('algorithm-visualizer'); +// } +// define tracer variables { const logger = new LogTracer(); Layout.setRoot(new VerticalLayout([logger])); Tracer.delay(); +// } for (let i = 0; i < 3; i++) { let a = Math.floor(Math.random() * 300); if (a % 2 === 0) a += 1; testProbablyPrime(a); + // visualize { logger.println('----------'); + // } } testProbablyPrime(151); +// visualize { logger.println('----------'); +// } testProbablyPrime(199, 10); @@ -39,14 +47,20 @@ function power(x, y, p) { * @return {Boolean} */ function testProbablyPrime(n, k = 5) { + // visualize { logger.println(`==> Testing number ${n}`); + // } if (n === 1 || n === 3) { + // visualize { logger.println('==> Simple case, N is 1 or 3'); + // } return true; } if (n % 2 === 0) { + // visualize { logger.println(`==> Simple case, ${n} mod 2 = 0`); + // } return false; } @@ -55,25 +69,35 @@ function testProbablyPrime(n, k = 5) { while (d % 2 === 0) { d /= 2; } + // visualize { logger.println(`d = ${d}`); + // } const P = 100 * (1 - (1 / Math.pow(4, k))); WitnessLoop: do { + // visualize { logger.println(`Remaining iterations: #${k}`); + // } const a = 2 + Math.floor(Math.random() * (n - 4)); + // visualize { logger.println(`--> first test with random = ${a}`); + // } // Compute a^d % n let x = power(a, d, n); if (x === 1 || x === n - 1) { + // visualize { logger.println('--> continue WitnessLoop, x = 1 or x = n-1'); + // } continue; } + // visualize { logger.println('--> second test'); + // } // Keep squaring x while one of the following doesn't // happen @@ -86,20 +110,28 @@ function testProbablyPrime(n, k = 5) { i *= 2; if (x === 1) { + // visualize { logger.println(`--> exiting, ${n} is composite`); + // } return false; } if (x === n - 1) { + // visualize { logger.println('--> continue WitnessLoop'); + // } continue WitnessLoop; } } + // visualize { logger.println(`--> exiting, ${n} is composite 'cause (n-1) is reached`); + // } return false; } while (--k); + // visualize { logger.println(`End of tests, ${n} is probably prime with probabilty of ${P}%`); + // } return true; }