Skip to content

Commit 3b1059d

Browse files
committed
feat: heap visualizer
1 parent ca852cf commit 3b1059d

File tree

4 files changed

+199
-1
lines changed

4 files changed

+199
-1
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
export function createHeap(type = "max") {
2+
let heap = [];
3+
const compare = (a, b) => (type === "max" ? a > b : a < b);
4+
5+
const swap = (i, j) => {
6+
[heap[i], heap[j]] = [heap[j], heap[i]];
7+
};
8+
9+
const heapifyUp = () => {
10+
let i = heap.length - 1;
11+
while (i > 0) {
12+
let p = Math.floor((i - 1) / 2);
13+
if (compare(heap[i], heap[p])) {
14+
swap(i, p);
15+
i = p;
16+
} else break;
17+
}
18+
};
19+
20+
const heapifyDown = () => {
21+
let i = 0;
22+
const n = heap.length;
23+
while (true) {
24+
let l = 2 * i + 1,
25+
r = 2 * i + 2,
26+
target = i; // ✅ changed from 'largest' → 'target' for clarity
27+
if (l < n && compare(heap[l], heap[target])) target = l;
28+
if (r < n && compare(heap[r], heap[target])) target = r;
29+
if (target === i) break;
30+
swap(i, target);
31+
i = target;
32+
}
33+
};
34+
35+
return {
36+
getHeap: () => [...heap],
37+
38+
insert: (val) => {
39+
heap.push(val);
40+
heapifyUp();
41+
return [...heap];
42+
},
43+
44+
deleteRoot: () => {
45+
if (heap.length === 0) return [];
46+
if (heap.length === 1) {
47+
heap.pop();
48+
return [];
49+
}
50+
51+
// ✅ fixed: replace root with last, pop last, then heapify
52+
heap[0] = heap[heap.length - 1];
53+
heap.pop();
54+
heapifyDown();
55+
return [...heap];
56+
},
57+
58+
reset: () => {
59+
heap = [];
60+
return [];
61+
},
62+
};
63+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
import { motion, AnimatePresence } from "framer-motion";
3+
4+
function getHeapLevels(heap) {
5+
const result = [];
6+
let levelStart = 0;
7+
let levelSize = 1;
8+
9+
while (levelStart < heap.length) {
10+
result.push(heap.slice(levelStart, levelStart + levelSize));
11+
levelStart += levelSize;
12+
levelSize *= 2;
13+
}
14+
15+
return result;
16+
}
17+
18+
export default function HeapVisualizer({ heap }) {
19+
const levels = getHeapLevels(heap);
20+
21+
return (
22+
<div className="flex flex-col items-center mt-10 space-y-8">
23+
<AnimatePresence>
24+
{levels.map((level, i) => (
25+
<motion.div
26+
key={i}
27+
className="flex justify-center space-x-8"
28+
initial={{ opacity: 0, y: 30 }}
29+
animate={{ opacity: 1, y: 0 }}
30+
exit={{ opacity: 0, y: -30 }}
31+
transition={{ duration: 0.4 }}
32+
>
33+
{level.map((val, j) => (
34+
<motion.div
35+
key={`${i}-${j}-${val}`}
36+
layout
37+
initial={{ scale: 0, opacity: 0 }}
38+
animate={{ scale: 1, opacity: 1 }}
39+
exit={{ scale: 0, opacity: 0 }}
40+
transition={{ duration: 0.4 }}
41+
className="bg-gradient-to-r from-purple-500 to-indigo-500 text-white font-semibold
42+
w-16 h-16 flex items-center justify-center rounded-2xl shadow-md
43+
transition-all duration-300 transform hover:scale-105"
44+
>
45+
{val}
46+
</motion.div>
47+
))}
48+
</motion.div>
49+
))}
50+
</AnimatePresence>
51+
</div>
52+
);
53+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React, { useState } from "react";
2+
import HeapVisualizer from "../../components/dataStructure/HeapVisualizer.jsx";
3+
import { createHeap } from "../../algorithms/dataStructure/heap.js";
4+
5+
export default function HeapPage() {
6+
const [heapType, setHeapType] = useState("min");
7+
const [heapObj, setHeapObj] = useState(() => createHeap(heapType));
8+
const [heap, setHeap] = useState([]);
9+
const [value, setValue] = useState("");
10+
11+
const insertValue = () => {
12+
if (!value.trim()) return;
13+
const updated = heapObj.insert(Number(value));
14+
setHeap(updated);
15+
setValue("");
16+
};
17+
18+
const deleteRoot = () => setHeap(heapObj.deleteRoot());
19+
const reset = () => {
20+
const cleared = heapObj.reset();
21+
setHeap(cleared);
22+
};
23+
24+
const toggleType = () => {
25+
const newType = heapType === "min" ? "max" : "min";
26+
const newHeap = createHeap(newType);
27+
setHeapType(newType);
28+
setHeapObj(newHeap);
29+
setHeap([]);
30+
};
31+
32+
return (
33+
<div className="flex flex-col items-center justify-center min-h-screen bg-black text-white">
34+
<h1 className="text-3xl font-bold mb-8 text-indigo-400 uppercase tracking-wide">
35+
{heapType.toUpperCase()} Heap Visualizer
36+
</h1>
37+
38+
<div className="flex gap-4 mb-6">
39+
<input
40+
type="number"
41+
value={value}
42+
onChange={(e) => setValue(e.target.value)}
43+
placeholder="Enter value"
44+
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"
45+
/>
46+
<button
47+
onClick={insertValue}
48+
className="px-4 py-2 rounded bg-purple-600 hover:bg-purple-700 transition font-semibold"
49+
>
50+
Insert
51+
</button>
52+
<button
53+
onClick={deleteRoot}
54+
className="px-4 py-2 rounded bg-red-600 hover:bg-red-700 transition font-semibold"
55+
>
56+
Delete Root
57+
</button>
58+
<button
59+
onClick={reset}
60+
className="px-4 py-2 rounded bg-gray-700 hover:bg-gray-600 transition font-semibold"
61+
>
62+
Reset
63+
</button>
64+
<button
65+
onClick={toggleType}
66+
className="px-4 py-2 rounded bg-fuchsia-600 hover:bg-fuchsia-700 transition font-semibold"
67+
>
68+
Switch to {heapType === "min" ? "Max" : "Min"} Heap
69+
</button>
70+
</div>
71+
72+
<HeapVisualizer heap={heap} />
73+
</div>
74+
);
75+
}

src/pages/dataStructure/datastructurePage.jsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import StackPage from "./stack.jsx";
44
import LinkedListPage from "./linkedlist.jsx"; // ✅ Linked List page import
55
import QueuePage from "./queue.jsx";
66
import BinaryTreePage from "./BinaryTreePage.jsx";
7-
7+
import HeapPage from "./HeapPage.jsx";
88

99
export default function DSPage() {
1010
const [selectedDS, setSelectedDS] = useState("");
@@ -37,6 +37,12 @@ export default function DSPage() {
3737
<BinaryTreePage />
3838
</div>
3939
);
40+
case "heap":
41+
return (
42+
<div className="w-full h-full overflow-auto">
43+
<HeapPage />
44+
</div>
45+
);
4046

4147

4248
default:
@@ -84,6 +90,7 @@ export default function DSPage() {
8490
<option value="queue">Queue</option>
8591
<option value="linkedlist">Linked List</option>
8692
<option value="binarytree">Binary Tree / BST</option>
93+
<option value="heap">Heap</option>
8794

8895
</select>
8996

0 commit comments

Comments
 (0)