From ec80445aaec2c7fe9fc796ae472c14f1d70351ad Mon Sep 17 00:00:00 2001 From: Tamim Ehsan Date: Mon, 4 Aug 2025 22:13:20 +0800 Subject: [PATCH 1/4] refactor: rename files --- src/app/recursion-tree/vertexOriginal.jsx | 76 ----------------------- src/lib/algorithms/{bfs.jsx => bfs.js} | 0 2 files changed, 76 deletions(-) delete mode 100644 src/app/recursion-tree/vertexOriginal.jsx rename src/lib/algorithms/{bfs.jsx => bfs.js} (100%) diff --git a/src/app/recursion-tree/vertexOriginal.jsx b/src/app/recursion-tree/vertexOriginal.jsx deleted file mode 100644 index 4637dd3..0000000 --- a/src/app/recursion-tree/vertexOriginal.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, {Component} from 'react'; - -class Vertex extends Component { - - constructor() { - super(); - this.state = { - prevPoss:{ - x:0, - y:0 - }, - poss:{ - x:0, - y:0, - xx:0, - yy:0 - }, - prevX:0 - } - } - - componentDidUpdate(prevProps) { - if (this.state.poss.x !== this.props.pos.x) { - let pp = this.state.poss; - pp.xx = pp.x; - pp.yy = pp.y; - pp.x = this.props.pos.x; - pp.y = this.props.pos.y; - this.setState({poss:pp}); - document.getElementById('vbanim').beginElement(); - } - } - render() { - - return ( - - - {/**/} - - - - {this.props.label} - - - - - - ); - } -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -export default Vertex; \ No newline at end of file diff --git a/src/lib/algorithms/bfs.jsx b/src/lib/algorithms/bfs.js similarity index 100% rename from src/lib/algorithms/bfs.jsx rename to src/lib/algorithms/bfs.js From acb95192680d2ff7ff2911489ed7c955246515d4 Mon Sep 17 00:00:00 2001 From: Tamim Ehsan Date: Mon, 4 Aug 2025 23:22:30 +0800 Subject: [PATCH 2/4] refactor: recursive tree components --- .../{recursion-tree => common/tree}/edge.jsx | 4 +-- .../tree}/vertex.jsx | 4 +-- src/app/recursion-tree/bst.js | 25 -------------- src/app/recursion-tree/canvasSVG.jsx | 8 ++--- src/app/recursion-tree/fib.jsx | 33 ++++++++++--------- src/{app/recursion-tree => lib/tree}/Tree.js | 2 +- 6 files changed, 26 insertions(+), 50 deletions(-) rename src/app/{recursion-tree => common/tree}/edge.jsx (98%) rename src/app/{recursion-tree => common/tree}/vertex.jsx (97%) delete mode 100644 src/app/recursion-tree/bst.js rename src/{app/recursion-tree => lib/tree}/Tree.js (99%) diff --git a/src/app/recursion-tree/edge.jsx b/src/app/common/tree/edge.jsx similarity index 98% rename from src/app/recursion-tree/edge.jsx rename to src/app/common/tree/edge.jsx index ff44400..91779fe 100644 --- a/src/app/recursion-tree/edge.jsx +++ b/src/app/common/tree/edge.jsx @@ -1,6 +1,6 @@ import React, {Component} from 'react'; -class Edge extends Component { +class TreeEdge extends Component { constructor() { super(); this.state={ @@ -91,4 +91,4 @@ class Edge extends Component { } } -export default Edge; \ No newline at end of file +export default TreeEdge; \ No newline at end of file diff --git a/src/app/recursion-tree/vertex.jsx b/src/app/common/tree/vertex.jsx similarity index 97% rename from src/app/recursion-tree/vertex.jsx rename to src/app/common/tree/vertex.jsx index ab72f8d..581834b 100644 --- a/src/app/recursion-tree/vertex.jsx +++ b/src/app/common/tree/vertex.jsx @@ -1,6 +1,6 @@ import React, {Component} from 'react'; -class Vertex extends Component { +class TreeVertex extends Component { constructor() { super(); @@ -80,4 +80,4 @@ function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } -export default Vertex; \ No newline at end of file +export default TreeVertex; \ No newline at end of file diff --git a/src/app/recursion-tree/bst.js b/src/app/recursion-tree/bst.js deleted file mode 100644 index 1f08782..0000000 --- a/src/app/recursion-tree/bst.js +++ /dev/null @@ -1,25 +0,0 @@ -class Node{ - constructor(val) { - this.val = val; - this.left = undefined; - this.right = undefined; - } -} -export class BST{ - constructor() { - this.root = undefined; - } - insert(x){ - this.root = this.insertX(x,this.root); - } - insertX(x,node){ - if( node === undefined ){ - return new Node(x); - return; - } - if( node.value === x ) return node; - else if( node.value > x ) node.left = this.insertX(x,node.left); - else node.right = this.insertX(x,node.right); - } - -} \ No newline at end of file diff --git a/src/app/recursion-tree/canvasSVG.jsx b/src/app/recursion-tree/canvasSVG.jsx index 8266246..f8c30f8 100644 --- a/src/app/recursion-tree/canvasSVG.jsx +++ b/src/app/recursion-tree/canvasSVG.jsx @@ -1,6 +1,6 @@ import { Component } from 'react'; -import Edge from "./edge"; -import Vertex from "./vertex"; +import TreeEdge from "../common/tree/edge"; +import TreeVertex from "../common/tree/vertex"; class CanvasSvg extends Component { constructor() { @@ -28,7 +28,7 @@ class CanvasSvg extends Component { { this.props.edges.map((edge, cellidx) => { return ( - { return ( - n) - return new Tree(-1,[],"("+n+","+r+")"); + return new TreeNode(-1,[],"("+n+","+r+")"); if (n === r) - return new Tree(1,[],"("+n+","+r+")"); + return new TreeNode(1,[],"("+n+","+r+")"); if (r === 0) - return new Tree(1,[],"("+n+","+r+")");; + return new TreeNode(1,[],"("+n+","+r+")");; // nCr(n, r) = nCr(n - 1, r - 1) + nCr(n - 1, r) - let tree = new Tree(0,[],"("+n+","+r+")"); + let tree = new TreeNode(0,[],"("+n+","+r+")"); tree.children.push( NcR(n-1,r-1) ); tree.children.push( NcR(n-1,r) ); tree.node = tree.children[0].node+tree.children[1].node; @@ -49,9 +50,9 @@ function NcR(n,r){ } function derangement(n){ - if( n == 0 ) return new Tree(1,[],n+""); - if( n == 1 ) return new Tree(0,[],n+""); - let tree = new Tree(0,[],n+""); + if( n == 0 ) return new TreeNode(1,[],n+""); + if( n == 1 ) return new TreeNode(0,[],n+""); + let tree = new TreeNode(0,[],n+""); tree.children.push( derangement(n-1) ); tree.children.push( derangement(n-2) ); tree.node = (n-1)*(tree.children[0].node+tree.children[1].node); @@ -59,9 +60,9 @@ function derangement(n){ } function bigmod(n,r){ - if( r === 0 ) return new Tree(1,[],"("+n+","+r+")"); - if( r === 1 ) return new Tree(n,[],"("+n+","+r+")"); - let tree = new Tree(1,[],"("+n+","+r+")"); + if( r === 0 ) return new TreeNode(1,[],"("+n+","+r+")"); + if( r === 1 ) return new TreeNode(n,[],"("+n+","+r+")"); + let tree = new TreeNode(1,[],"("+n+","+r+")"); if( r%2 === 1 ){ tree.children.push( bigmod(n,(r-1)/2 ) ); tree.children.push( bigmod(n,(r-1)/2) ); @@ -77,10 +78,10 @@ function bigmod(n,r){ } function stirling2(n,r){ - if( n === r ) return new Tree(1,[],"("+n+","+r+")"); - if( r === 0 ) return new Tree(0,[],"("+n+","+r+")"); + if( n === r ) return new TreeNode(1,[],"("+n+","+r+")"); + if( r === 0 ) return new TreeNode(0,[],"("+n+","+r+")"); - let tree = new Tree(0,[],"("+n+","+r+")"); + let tree = new TreeNode(0,[],"("+n+","+r+")"); tree.children.push( stirling2(n-1,r) ); tree.children.push( stirling2(n-1,r-1) ); tree.node = tree.children[0].node*r+tree.children[1].node; diff --git a/src/app/recursion-tree/Tree.js b/src/lib/tree/Tree.js similarity index 99% rename from src/app/recursion-tree/Tree.js rename to src/lib/tree/Tree.js index 5137bf3..c20cb5a 100644 --- a/src/app/recursion-tree/Tree.js +++ b/src/lib/tree/Tree.js @@ -1,7 +1,7 @@ // draw tree class functions start :/ -export class Tree{ +export class TreeNode { constructor(node=0,children=[],label="") { this.id = 0; this.node = node; From e9d9dd34fe741a020bfc8bbd054216bf7c72fb97 Mon Sep 17 00:00:00 2001 From: Tamim Ehsan Date: Mon, 4 Aug 2025 23:27:11 +0800 Subject: [PATCH 3/4] refactor: rename files --- .../common/tree/{edge.jsx => TreeEdge.jsx} | 0 .../tree/{vertex.jsx => TreeVertex.jsx} | 0 src/app/recursion-tree/canvasSVG.jsx | 4 +- src/app/recursion-tree/details.jsx | 115 ------------------ 4 files changed, 2 insertions(+), 117 deletions(-) rename src/app/common/tree/{edge.jsx => TreeEdge.jsx} (100%) rename src/app/common/tree/{vertex.jsx => TreeVertex.jsx} (100%) delete mode 100644 src/app/recursion-tree/details.jsx diff --git a/src/app/common/tree/edge.jsx b/src/app/common/tree/TreeEdge.jsx similarity index 100% rename from src/app/common/tree/edge.jsx rename to src/app/common/tree/TreeEdge.jsx diff --git a/src/app/common/tree/vertex.jsx b/src/app/common/tree/TreeVertex.jsx similarity index 100% rename from src/app/common/tree/vertex.jsx rename to src/app/common/tree/TreeVertex.jsx diff --git a/src/app/recursion-tree/canvasSVG.jsx b/src/app/recursion-tree/canvasSVG.jsx index f8c30f8..8b8de0b 100644 --- a/src/app/recursion-tree/canvasSVG.jsx +++ b/src/app/recursion-tree/canvasSVG.jsx @@ -1,6 +1,6 @@ import { Component } from 'react'; -import TreeEdge from "../common/tree/edge"; -import TreeVertex from "../common/tree/vertex"; +import TreeEdge from "../common/tree/TreeEdge"; +import TreeVertex from "../common/tree/TreeVertex"; class CanvasSvg extends Component { constructor() { diff --git a/src/app/recursion-tree/details.jsx b/src/app/recursion-tree/details.jsx deleted file mode 100644 index adc3e02..0000000 --- a/src/app/recursion-tree/details.jsx +++ /dev/null @@ -1,115 +0,0 @@ -import React, {Component} from 'react'; - -class Details extends Component { - - Switcherr = () => { - switch (this.props.algo) { - case 0: - return
-
- The Fibonacci sequence, in which each number is the sum of the two preceding ones. The sequence - commonly starts from 0 and 1 -
-
- N = Nth fibonacchi Number -
-
- function = nCr(n,r) -
-
- Fib(0) = 0
- Fib(1) = 1
- Fib(n) = Fib(n-1) + Fib(n-2) -
-
; - - case 1: - return
-
- In mathematics, the binomial coefficients are the positive integers that occur as coefficients - in the binomial theorem. It is the coefficient of - the x^k term in the polynomial expansion of the binomial power (1+x)^n -
-
- nCr = n! / ( k! * (n-k)! ) -
-
- function = nCr(n,r) -
-
- nCr(a,a) = 1
- nCr(a,0) = 1
- nCr(n,r) = nCr(n-1,r-1)+nCr(n-1,r) -
-
; - case 2: - return
-
- In combinatorial mathematics, a derangement is a permutation of the elements of a set, such that - no element appears in its original position. -
-
- N = Nth Derangement -
-
- function = der(n) -
-
- der(0) = 1
- der(1) = 0
- der(n) = (n-1) * ( der(n-1) + der(n-2) ) -
-
; - case 3: - return
-
- N = Number - P = Power -
-
- function = bigmod(n,p) -
-
- bigmod(a,0) = 1
- bigmod(a,1) = a
- bigmod(n,p) = bigmod(n,p/2)^2; p is even
- bigmod(n,p) = bigmod(n,(p-1)/2)^2 * n ; p is odd -
-
; - case 4: - return
-
- a Stirling number of the second kind (or Stirling partition number) is the number of ways to - partition a set of n objects into k non-empty subsets -
-
- N = Row - R = Column -
-
- function = stir2(n,r) -
-
- stir2(a,a) = 1
- stir2(0,a) = 0
- stir2(n,r) = stir2(n-1,r) * r + stir2(n-1,r-1) - -
-
; - - default: - return Henlo; - - } - } - - render() { - return ( -
- {this.Switcherr()} -
- ); - } -} - -export default Details; \ No newline at end of file From 4492a6f2014ca54f87d12c7dfe7958689ef8e718 Mon Sep 17 00:00:00 2001 From: Tamim Ehsan Date: Mon, 4 Aug 2025 23:42:54 +0800 Subject: [PATCH 4/4] draft: heap implementation --- src/app/components/algorithm-cards.jsx | 6 + src/app/heap/canvasSVG.jsx | 46 +++++++ src/app/heap/menu.jsx | 88 ++++++++++++++ src/app/heap/page.jsx | 158 +++++++++++++++++++++++++ src/lib/heap/Heap.js | 121 +++++++++++++++++++ 5 files changed, 419 insertions(+) create mode 100644 src/app/heap/canvasSVG.jsx create mode 100644 src/app/heap/menu.jsx create mode 100644 src/app/heap/page.jsx create mode 100644 src/lib/heap/Heap.js diff --git a/src/app/components/algorithm-cards.jsx b/src/app/components/algorithm-cards.jsx index 87647eb..5f15922 100644 --- a/src/app/components/algorithm-cards.jsx +++ b/src/app/components/algorithm-cards.jsx @@ -29,6 +29,12 @@ const algorithms = [ description: "Compare different recursive sorting algorithms", image: '/AlgorithmVisualizer/images/sort.png?height=200&width=300' }, + { + id: 'heap', + title: 'Heap Visualization', + description: "Visualize heap data structure operations like insert and delete with max/min heap support", + image: '/AlgorithmVisualizer/images/heap.png?height=200&width=300' + }, { id: 'n-queen', title: 'N Queen', diff --git a/src/app/heap/canvasSVG.jsx b/src/app/heap/canvasSVG.jsx new file mode 100644 index 0000000..5b2ef32 --- /dev/null +++ b/src/app/heap/canvasSVG.jsx @@ -0,0 +1,46 @@ +import { Component } from 'react'; +import TreeEdge from "../common/tree/TreeEdge"; +import TreeVertex from "../common/tree/TreeVertex"; + +class CanvasSvg extends Component { + render() { + let off = this.props.offset; + + return ( +
+ + {this.props.edges.map((edge, index) => ( + + ))} + + {this.props.vertices.map((vertex, index) => ( + + ))} + +
+ ); + } +} + +export default CanvasSvg; diff --git a/src/app/heap/menu.jsx b/src/app/heap/menu.jsx new file mode 100644 index 0000000..61d1e8b --- /dev/null +++ b/src/app/heap/menu.jsx @@ -0,0 +1,88 @@ +import { CustomSelect } from '@/components/custom-select'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +// import { div } from '@/components/ui/div'; +import { Component } from 'react'; + +class Menu extends Component { + handleInputChange = (event) => { + const value = parseInt(event.target.value) || 0; + this.props.setInputValue(value); + } + + handleHeapTypeChange = (index) => { + this.props.setHeapType(index === 0); // 0 = Max Heap, 1 = Min Heap + } + + render() { + return ( +
+

Heap Controls

+ + + +
+
Value to Insert
+ +
+ +
+
Heap Info
+
+

Type: {this.props.isMaxHeap ? 'Max Heap' : 'Min Heap'}

+

Size: {this.props.heapSize}

+
+
+ + + + + + +
+ ); + } + + isClickable = () => { + if (this.props.disable) { + return { cursor: "not-allowed" }; + } else { + return {}; + } + } +} + +export default Menu; diff --git a/src/app/heap/page.jsx b/src/app/heap/page.jsx new file mode 100644 index 0000000..dd70d7e --- /dev/null +++ b/src/app/heap/page.jsx @@ -0,0 +1,158 @@ +"use client"; + +import Navbar from '@/components/navbar'; +import { Component } from 'react'; +import CanvasSvg from "./canvasSVG"; +import { Heap } from "@/lib/heap/Heap"; +import Menu from "./menu"; + +class HeapVisualization extends Component { + constructor() { + super(); + this.state = { + heap: new Heap(true), // true for max heap + vertices: [], + edges: [], + current: -1, + isMaxHeap: true, + inputValue: 0, + offset: 0, + animating: false + } + } + + setHeapType = (isMaxHeap) => { + this.setState({ + heap: new Heap(isMaxHeap), + isMaxHeap, + vertices: [], + edges: [], + offset: 0 + }); + } + + setInputValue = (value) => { + this.setState({ inputValue: value }); + } + + pushValue = async () => { + if (this.state.animating) return; + + this.setState({ animating: true }); + const heap = this.state.heap; + heap.push(this.state.inputValue); + + await this.updateVisualization(); + this.setState({ animating: false }); + } + + popValue = async () => { + if (this.state.animating || this.state.heap.heap.length === 0) return; + + this.setState({ animating: true }); + const heap = this.state.heap; + heap.pop(); + + await this.updateVisualization(); + this.setState({ animating: false }); + } + + reset = () => { + this.setState({ + heap: new Heap(this.state.isMaxHeap), + vertices: [], + edges: [], + offset: 0, + current: -1 + }); + } + + updateVisualization = async () => { + const tree = this.state.heap.getVisualizationTree(); + + if (!tree) { + this.setState({ vertices: [], edges: [], offset: 0 }); + return; + } + + this.setState({ + edges: [], + vertices: [], + offset: tree.x + }); + + await this.buildVisualization(tree, undefined); + } + + buildVisualization = async (node, parent) => { + let vertices = this.state.vertices; + let current = vertices.length; + + const vertexData = { + label: node.tree.label, + val: node.tree.node, + x: node.x, + y: node.y, + px: parent ? parent.x : node.x, + py: parent ? parent.y : node.y + }; + + vertices.push(vertexData); + this.setState({ vertices: [...vertices], current }); + + if (parent) { + let edges = this.state.edges; + edges.push({ + x1: parent.x, + y1: parent.y, + x2: node.x, + y2: node.y + }); + this.setState({ edges: [...edges] }); + } + + await sleep(300); + + for (let i = 0; i < node.children.length; i++) { + await this.buildVisualization(node.children[i], node); + } + } + + render() { + return ( +
+ +
+ + +
+
+ +
+
+
+
+ ); + } +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export default HeapVisualization; diff --git a/src/lib/heap/Heap.js b/src/lib/heap/Heap.js new file mode 100644 index 0000000..ae49079 --- /dev/null +++ b/src/lib/heap/Heap.js @@ -0,0 +1,121 @@ +import { TreeNode, buchheim } from '@/lib/tree/Tree'; + +export class Heap { + constructor(isMaxHeap = true) { + this.heap = []; + this.isMaxHeap = isMaxHeap; + this.operations = []; + } + + compare(a, b) { + return this.isMaxHeap ? a > b : a < b; + } + + parent(index) { + return Math.floor((index - 1) / 2); + } + + leftChild(index) { + return 2 * index + 1; + } + + rightChild(index) { + return 2 * index + 2; + } + + swap(i, j) { + [this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]; + } + + push(value) { + this.heap.push(value); + this.heapifyUp(this.heap.length - 1); + this.operations.push({ + type: 'push', + value: value, + heap: [...this.heap] + }); + } + + pop() { + if (this.heap.length === 0) return null; + + const root = this.heap[0]; + const lastElement = this.heap.pop(); + + if (this.heap.length > 0) { + this.heap[0] = lastElement; + this.heapifyDown(0); + } + + this.operations.push({ + type: 'pop', + value: root, + heap: [...this.heap] + }); + + return root; + } + + heapifyUp(index) { + if (index === 0) return; + + const parentIndex = this.parent(index); + if (this.compare(this.heap[index], this.heap[parentIndex])) { + this.swap(index, parentIndex); + this.heapifyUp(parentIndex); + } + } + + heapifyDown(index) { + let targetIndex = index; + const leftIndex = this.leftChild(index); + const rightIndex = this.rightChild(index); + + if (leftIndex < this.heap.length && + this.compare(this.heap[leftIndex], this.heap[targetIndex])) { + targetIndex = leftIndex; + } + + if (rightIndex < this.heap.length && + this.compare(this.heap[rightIndex], this.heap[targetIndex])) { + targetIndex = rightIndex; + } + + if (targetIndex !== index) { + this.swap(index, targetIndex); + this.heapifyDown(targetIndex); + } + } + + toTreeNode() { + if (this.heap.length === 0) return null; + return this.buildTreeNode(0); + } + + buildTreeNode(index) { + if (index >= this.heap.length) return null; + + const children = []; + const leftIndex = this.leftChild(index); + const rightIndex = this.rightChild(index); + + if (leftIndex < this.heap.length) { + children.push(this.buildTreeNode(leftIndex)); + } + if (rightIndex < this.heap.length) { + children.push(this.buildTreeNode(rightIndex)); + } + + return new TreeNode( + this.heap[index], + children.filter(child => child !== null), + this.heap[index].toString() + ); + } + + getVisualizationTree() { + const treeNode = this.toTreeNode(); + return treeNode ? buchheim(treeNode) : null; + } +}