From 3b1059d1af47aeb53ea08bc36786bcee281d8e4b Mon Sep 17 00:00:00 2001 From: shivam7147 Date: Fri, 31 Oct 2025 19:37:59 +0530 Subject: [PATCH] feat: heap visualizer --- src/algorithms/dataStructure/heap.js | 63 ++++++++++++++++ .../dataStructure/HeapVisualizer.jsx | 53 +++++++++++++ src/pages/dataStructure/HeapPage.jsx | 75 +++++++++++++++++++ src/pages/dataStructure/datastructurePage.jsx | 9 ++- 4 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 src/algorithms/dataStructure/heap.js create mode 100644 src/components/dataStructure/HeapVisualizer.jsx create mode 100644 src/pages/dataStructure/HeapPage.jsx diff --git a/src/algorithms/dataStructure/heap.js b/src/algorithms/dataStructure/heap.js new file mode 100644 index 0000000..a8b45b8 --- /dev/null +++ b/src/algorithms/dataStructure/heap.js @@ -0,0 +1,63 @@ +export function createHeap(type = "max") { + let heap = []; + const compare = (a, b) => (type === "max" ? a > b : a < b); + + const swap = (i, j) => { + [heap[i], heap[j]] = [heap[j], heap[i]]; + }; + + const heapifyUp = () => { + let i = heap.length - 1; + while (i > 0) { + let p = Math.floor((i - 1) / 2); + if (compare(heap[i], heap[p])) { + swap(i, p); + i = p; + } else break; + } + }; + + const heapifyDown = () => { + let i = 0; + const n = heap.length; + while (true) { + let l = 2 * i + 1, + r = 2 * i + 2, + target = i; // ✅ changed from 'largest' → 'target' for clarity + if (l < n && compare(heap[l], heap[target])) target = l; + if (r < n && compare(heap[r], heap[target])) target = r; + if (target === i) break; + swap(i, target); + i = target; + } + }; + + return { + getHeap: () => [...heap], + + insert: (val) => { + heap.push(val); + heapifyUp(); + return [...heap]; + }, + + deleteRoot: () => { + if (heap.length === 0) return []; + if (heap.length === 1) { + heap.pop(); + return []; + } + + // ✅ fixed: replace root with last, pop last, then heapify + heap[0] = heap[heap.length - 1]; + heap.pop(); + heapifyDown(); + return [...heap]; + }, + + reset: () => { + heap = []; + return []; + }, + }; +} diff --git a/src/components/dataStructure/HeapVisualizer.jsx b/src/components/dataStructure/HeapVisualizer.jsx new file mode 100644 index 0000000..bfe3e86 --- /dev/null +++ b/src/components/dataStructure/HeapVisualizer.jsx @@ -0,0 +1,53 @@ +import React from "react"; +import { motion, AnimatePresence } from "framer-motion"; + +function getHeapLevels(heap) { + const result = []; + let levelStart = 0; + let levelSize = 1; + + while (levelStart < heap.length) { + result.push(heap.slice(levelStart, levelStart + levelSize)); + levelStart += levelSize; + levelSize *= 2; + } + + return result; +} + +export default function HeapVisualizer({ heap }) { + const levels = getHeapLevels(heap); + + return ( +
+ + {levels.map((level, i) => ( + + {level.map((val, j) => ( + + {val} + + ))} + + ))} + +
+ ); +} diff --git a/src/pages/dataStructure/HeapPage.jsx b/src/pages/dataStructure/HeapPage.jsx new file mode 100644 index 0000000..04549df --- /dev/null +++ b/src/pages/dataStructure/HeapPage.jsx @@ -0,0 +1,75 @@ +import React, { useState } from "react"; +import HeapVisualizer from "../../components/dataStructure/HeapVisualizer.jsx"; +import { createHeap } from "../../algorithms/dataStructure/heap.js"; + +export default function HeapPage() { + const [heapType, setHeapType] = useState("min"); + const [heapObj, setHeapObj] = useState(() => createHeap(heapType)); + const [heap, setHeap] = useState([]); + const [value, setValue] = useState(""); + + const insertValue = () => { + if (!value.trim()) return; + const updated = heapObj.insert(Number(value)); + setHeap(updated); + setValue(""); + }; + + const deleteRoot = () => setHeap(heapObj.deleteRoot()); + const reset = () => { + const cleared = heapObj.reset(); + setHeap(cleared); + }; + + const toggleType = () => { + const newType = heapType === "min" ? "max" : "min"; + const newHeap = createHeap(newType); + setHeapType(newType); + setHeapObj(newHeap); + setHeap([]); + }; + + return ( +
+

+ {heapType.toUpperCase()} Heap Visualizer +

+ +
+ setValue(e.target.value)} + placeholder="Enter value" + className="px-4 py-2 rounded bg-gray-800 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-purple-500" + /> + + + + +
+ + +
+ ); +} diff --git a/src/pages/dataStructure/datastructurePage.jsx b/src/pages/dataStructure/datastructurePage.jsx index e799083..fdf2562 100644 --- a/src/pages/dataStructure/datastructurePage.jsx +++ b/src/pages/dataStructure/datastructurePage.jsx @@ -4,7 +4,7 @@ import StackPage from "./stack.jsx"; import LinkedListPage from "./linkedlist.jsx"; // ✅ Linked List page import import QueuePage from "./queue.jsx"; import BinaryTreePage from "./BinaryTreePage.jsx"; - +import HeapPage from "./HeapPage.jsx"; export default function DSPage() { const [selectedDS, setSelectedDS] = useState(""); @@ -37,6 +37,12 @@ export default function DSPage() { ); + case "heap": + return ( +
+ +
+ ); default: @@ -84,6 +90,7 @@ export default function DSPage() { +