Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Binary Min-Heap Animation</title>
<style>
body { margin: 0; overflow: hidden; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; }
canvas { border: 1px solid #000; }
#info { position: absolute; top: 20px; left: 20px; font-family: Arial, sans-serif; color: #333; }
</style>
</head>
<body>
<div id="info"></div><canvas id="heapCanvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('heapCanvas');
const ctx = canvas.getContext('2d');
const infoDiv = document.getElementById('info');
let insertCount = 0;
let extractCount = 0;
let heap = [];
let radius = 30;
function drawCircle(x, y, value, highlight) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = highlight ? 'yellow' : 'white';
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.fill();
ctx.stroke();
ctx.font = '16px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#000';
ctx.fillText(value, x, y);
}
function drawEdge(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.stroke();
}
function getCoordinates(index, levelCount) {
const xOffset = canvas.width / (levelCount + 1);
const yOffset = radius * 3;
const level = Math.floor(Math.log2(index + 1));
const row = level * yOffset;
const col = index - Math.pow(2, level) + 1;
return { x: col * xOffset, y: row };
}
function drawHeap() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < heap.length; i++) {
const coords = getCoordinates(i, Math.ceil(Math.log2(heap.length + 1)));
drawCircle(coords.x, coords.y, heap[i], false);
if (i > 0) {
const parentCoords = getCoordinates(Math.floor((i - 1) / 2), Math.ceil(Math.log2(heap.length + 1)));
drawEdge(parentCoords.x, parentCoords.y, coords.x, coords.y);
}
}
}
function heapifyUp(index) {
let currentIndex = index;
while (currentIndex > 0 && heap[currentIndex] < heap[Math.floor((currentIndex - 1) / 2)]) {
const parentIndex = Math.floor((currentIndex - 1) / 2);
[heap[currentIndex], heap[parentIndex]] = [heap[parentIndex], heap[currentIndex]];
drawHeap();
let swapCoords = getCoordinates(currentIndex, Math.ceil(Math.log2(heap.length + 1)));
let parentSwapCoords = getCoordinates(parentIndex, Math.ceil(Math.log2(heap.length + 1)));
ctx.clearRect(swapCoords.x - radius, swapCoords.y - radius, radius * 2, radius * 2);
ctx.clearRect(parentSwapCoords.x - radius, parentSwapCoords.y - radius, radius * 2, radius * 2);
drawCircle(swapCoords.x, swapCoords.y, heap[currentIndex], true);
drawCircle(parentSwapCoords.x, parentSwapCoords.y, heap[parentIndex], false);
yield;
ctx.clearRect(swapCoords.x - radius, swapCoords.y - radius, radius * 2, radius * 2);
ctx.clearRect(parentSwapCoords.x - radius, parentSwapCoords.y - radius, radius * 2, radius * 2);
drawCircle(swapCoords.x, swapCoords.y, heap[currentIndex], false);
drawCircle(parentSwapCoords.x, parentSwapCoords.y, heap[parentIndex], false);
currentIndex = parentIndex;
}
}
function heapifyDown(index) {
let currentIndex = index;
while (2 * currentIndex + 1 < heap.length) {
const leftChildIndex = 2 * currentIndex + 1;
const rightChildIndex = 2 * currentIndex + 2;
let smallestIndex = currentIndex;
if (heap[leftChildIndex] < heap[smallestIndex]) {
smallestIndex = leftChildIndex;
}
if (rightChildIndex < heap.length && heap[rightChildIndex] < heap[smallestIndex]) {
smallestIndex = rightChildIndex;
}
if (currentIndex === smallestIndex) break;
[heap[currentIndex], heap[smallestIndex]] = [heap[smallestIndex], heap[currentIndex]];
drawHeap();
let swapCoords = getCoordinates(currentIndex, Math.ceil(Math.log2(heap.length + 1)));
let childSwapCoords = getCoordinates(smallestIndex, Math.ceil(Math.log2(heap.length + 1)));
ctx.clearRect(swapCoords.x - radius, swapCoords.y - radius, radius * 2, radius * 2);
ctx.clearRect(childSwapCoords.x - radius, childSwapCoords.y - radius, radius * 2, radius * 2);
drawCircle(swapCoords.x, swapCoords.y, heap[currentIndex], true);
drawCircle(childSwapCoords.x, childSwapCoords.y, heap[smallestIndex], false);
yield;
ctx.clearRect(swapCoords.x - radius, swapCoords.y - radius, radius * 2, radius * 2);
ctx.clearRect(childSwapCoords.x - radius, childSwapCoords.y - radius, radius * 2, radius * 2);
drawCircle(swapCoords.x, swapCoords.y, heap[currentIndex], false);
drawCircle(childSwapCoords.x, childSwapCoords.y, heap[smallestIndex], false);
currentIndex = smallestIndex;
}
}
async function insertRandomValue() {
const value = Math.floor(Math.random() * 100);
heap.push(value);
await heapifyUp(heap.length - 1)[Symbol.asyncIterator]().next();
drawHeap();
infoDiv.innerText = `Inserts: ${++insertCount}, Extracts: ${extractCount}`;
}
async function extractMin() {
if (heap.length === 0) return;
const minValue = heap[0];
heap[0] = heap.pop();
await heapifyDown(0)[Symbol.asyncIterator]().next();
drawHeap();
infoDiv.innerText = `Inserts: ${insertCount}, Extracts: ${++extractCount}`;
}
async function runAnimation() {
while (true) {
for (let i = 0; i < 5 && heap.length < 20; i++) {
await insertRandomValue();
}
if (heap.length > 1) {
await extractMin();
} else {
return;
}
}
}
runAnimation().then(() => setTimeout(runAnimation, 3000));
</script>
</body>
</html>
```