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; }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: