updating the animation

This commit is contained in:
Jidong Xiao
2025-04-21 17:10:37 -04:00
committed by JamesFlare1212
parent c24a7592ab
commit 7b9d3983ed

View File

@@ -1,5 +1,3 @@
//AUTHOR: Chloe Lee
// initial array to be sorted // initial array to be sorted
let array = [5, 3, 8, 1, 9, 4]; let array = [5, 3, 8, 1, 9, 4];
let currentStep = 0; let currentStep = 0;
@@ -32,7 +30,6 @@ const codeLines = [
]; ];
function initialize() { function initialize() {
// Display code with line numbers
const codeElement = document.getElementById('code'); const codeElement = document.getElementById('code');
let codeHTML = ''; let codeHTML = '';
@@ -106,6 +103,8 @@ function updateArrayDisplay() {
element.classList.add('swap'); element.classList.add('swap');
} else if (animationSteps[currentStep] && animationSteps[currentStep].sorted && animationSteps[currentStep].sorted.includes(index)) { } else if (animationSteps[currentStep] && animationSteps[currentStep].sorted && animationSteps[currentStep].sorted.includes(index)) {
element.classList.add('done'); element.classList.add('done');
} else if (animationSteps[currentStep] && animationSteps[currentStep].activeHeap && index < animationSteps[currentStep].heapSize) {
element.classList.add('active-heap');
} }
element.textContent = value; element.textContent = value;
@@ -185,7 +184,6 @@ function drawHeapTree() {
} }
} }
// !! subject to change !!
for (let i = 0; i < Math.min(array.length, positions.length); i++) { for (let i = 0; i < Math.min(array.length, positions.length); i++) {
if (i < heapSize) { if (i < heapSize) {
// determine node color based on current operation // determine node color based on current operation
@@ -204,6 +202,10 @@ function drawHeapTree() {
animationSteps[currentStep].sorted.includes(i)) { animationSteps[currentStep].sorted.includes(i)) {
nodeColor = '#81ecec'; nodeColor = '#81ecec';
borderColor = '#00cec9'; borderColor = '#00cec9';
} else if (animationSteps[currentStep] && animationSteps[currentStep].activeHeap && i < animationSteps[currentStep].heapSize) {
// highlight active heap nodes
nodeColor = '#a3d8f4';
borderColor = '#0984e3';
} }
// draw rectangle with round corners // draw rectangle with round corners
@@ -244,18 +246,21 @@ function drawHeapTree() {
function generateAnimationSteps() { function generateAnimationSteps() {
animationSteps = []; animationSteps = [];
let tempArray = [...array]; const originalArray = [5, 3, 8, 1, 9, 4];
let tempArray = [...originalArray];
const n = tempArray.length; const n = tempArray.length;
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 0, line: 0,
description: 'Starting heap sort with array [' + tempArray.join(', ') + ']', description: 'Starting heap sort with array [' + originalArray.join(', ') + ']',
heapSize: n heapSize: n
}); });
// build max-heap // build max-heap
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 2, line: 2,
description: 'Building max heap', description: 'Building max heap',
heapSize: n heapSize: n
@@ -265,26 +270,36 @@ function generateAnimationSteps() {
for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 3, line: 3,
description: `Heapifying subtree rooted at index ${i}`, description: `Heapifying subtree rooted at index ${i}`,
heapSize: n, heapSize: n,
comparing: [i] comparing: [i]
}); });
heapifyWithAnimation(tempArray, n, i, sortedIndices); heapifyWithAnimation(tempArray, n, i, sortedIndices, originalArray);
} }
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 6, line: 6,
description: 'Max heap built. Extracting elements one by one', description: 'Max heap built. Extracting elements one by one',
heapSize: n heapSize: n
}); });
for (let i = n - 1; i > 0; i--) { for (let i = n - 1; i > 0; i--) {
// highlight the active heap portion before swap
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 7,
description: `Current active heap size: ${i+1}. Elements from index 0 to ${i} need to be processed.`,
heapSize: i + 1,
activeHeap: true,
sorted: [...sortedIndices]
});
animationSteps.push({
array: [...originalArray],
line: 8, line: 8,
description: `Swapping root (${tempArray[0]}) with element at index ${i} (${tempArray[i]})`, description: `Swapping root (${tempArray[0]}) with element at index ${i} (${tempArray[i]})`,
heapSize: i + 1, heapSize: i + 1,
@@ -297,7 +312,7 @@ function generateAnimationSteps() {
sortedIndices.push(i); sortedIndices.push(i);
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 8, line: 8,
description: `Element ${tempArray[i]} is now in its correct position`, description: `Element ${tempArray[i]} is now in its correct position`,
heapSize: i, heapSize: i,
@@ -305,18 +320,20 @@ function generateAnimationSteps() {
}); });
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 11, line: 11,
description: `Heapifying reduced heap (size ${i})`, description: `Heapifying reduced heap (size ${i})`,
heapSize: i heapSize: i,
activeHeap: true,
sorted: [...sortedIndices]
}); });
heapifyWithAnimation(tempArray, i, 0, sortedIndices); heapifyWithAnimation(tempArray, i, 0, sortedIndices, originalArray);
} }
sortedIndices.push(0); sortedIndices.push(0);
animationSteps.push({ animationSteps.push({
array: [...tempArray], array: [...originalArray],
line: 13, line: 13,
description: 'Heap sort complete! Array is now sorted: [' + tempArray.join(', ') + ']', description: 'Heap sort complete! Array is now sorted: [' + tempArray.join(', ') + ']',
heapSize: n, heapSize: n,
@@ -325,13 +342,13 @@ function generateAnimationSteps() {
} }
// heapify function that records animation steps // heapify function that records animation steps
function heapifyWithAnimation(arr, n, i, sortedIndices) { function heapifyWithAnimation(arr, n, i, sortedIndices, originalArray) {
let largest = i; let largest = i;
const left = 2 * i + 1; const left = 2 * i + 1;
const right = 2 * i + 2; const right = 2 * i + 2;
animationSteps.push({ animationSteps.push({
array: [...arr], array: [...originalArray],
line: 16, line: 16,
description: `Heapifying at index ${i}`, description: `Heapifying at index ${i}`,
heapSize: n, heapSize: n,
@@ -342,7 +359,7 @@ function heapifyWithAnimation(arr, n, i, sortedIndices) {
// compare with left child // compare with left child
if (left < n) { if (left < n) {
animationSteps.push({ animationSteps.push({
array: [...arr], array: [...originalArray],
line: 21, line: 21,
description: `Comparing ${arr[i]} (index ${i}) with left child ${arr[left]} (index ${left})`, description: `Comparing ${arr[i]} (index ${i}) with left child ${arr[left]} (index ${left})`,
heapSize: n, heapSize: n,
@@ -354,20 +371,39 @@ function heapifyWithAnimation(arr, n, i, sortedIndices) {
largest = left; largest = left;
animationSteps.push({ animationSteps.push({
array: [...arr], array: [...originalArray],
line: 22, line: 22,
description: `Left child ${arr[left]} is larger than current largest ${arr[i]}`, description: `Left child ${arr[left]} is larger than current largest ${arr[i]}`,
heapSize: n, heapSize: n,
comparing: [largest], comparing: [largest],
sorted: sortedIndices ? [...sortedIndices] : [] sorted: sortedIndices ? [...sortedIndices] : []
}); });
} else {
animationSteps.push({
array: [...originalArray],
line: 21,
description: `No action needed: ${arr[i]} (index ${i}) is already larger than or equal to its left child ${arr[left]} (index ${left})`,
heapSize: n,
comparing: [i],
sorted: sortedIndices ? [...sortedIndices] : []
});
} }
} else {
// no left child
animationSteps.push({
array: [...originalArray],
line: 21,
description: `No left child exists for node at index ${i}`,
heapSize: n,
comparing: [i],
sorted: sortedIndices ? [...sortedIndices] : []
});
} }
// compare with right child // compare with right child
if (right < n) { if (right < n) {
animationSteps.push({ animationSteps.push({
array: [...arr], array: [...originalArray],
line: 25, line: 25,
description: `Comparing ${arr[largest]} (index ${largest}) with right child ${arr[right]} (index ${right})`, description: `Comparing ${arr[largest]} (index ${largest}) with right child ${arr[right]} (index ${right})`,
heapSize: n, heapSize: n,
@@ -379,20 +415,39 @@ function heapifyWithAnimation(arr, n, i, sortedIndices) {
largest = right; largest = right;
animationSteps.push({ animationSteps.push({
array: [...arr], array: [...originalArray],
line: 26, line: 26,
description: `Right child ${arr[right]} is larger than current largest ${arr[largest === i ? arr[i] : arr[left]]}`, description: `Right child ${arr[right]} is larger than current largest ${arr[largest === i ? arr[i] : arr[left]]}`,
heapSize: n, heapSize: n,
comparing: [largest], comparing: [largest],
sorted: sortedIndices ? [...sortedIndices] : [] sorted: sortedIndices ? [...sortedIndices] : []
}); });
} else {
animationSteps.push({
array: [...originalArray],
line: 25,
description: `No action needed: ${arr[largest]} (index ${largest}) is already larger than or equal to its right child ${arr[right]} (index ${right})`,
heapSize: n,
comparing: [largest],
sorted: sortedIndices ? [...sortedIndices] : []
});
} }
} else {
// there is no right child
animationSteps.push({
array: [...originalArray],
line: 25,
description: `No right child exists for node at index ${i}`,
heapSize: n,
comparing: [i],
sorted: sortedIndices ? [...sortedIndices] : []
});
} }
// if largest is not root, swap and heapify // if largest is not root, swap and heapify
if (largest !== i) { if (largest !== i) {
animationSteps.push({ animationSteps.push({
array: [...arr], array: [...originalArray],
line: 30, line: 30,
description: `Swapping ${arr[i]} (index ${i}) with ${arr[largest]} (index ${largest})`, description: `Swapping ${arr[i]} (index ${i}) with ${arr[largest]} (index ${largest})`,
heapSize: n, heapSize: n,
@@ -403,7 +458,7 @@ function heapifyWithAnimation(arr, n, i, sortedIndices) {
[arr[i], arr[largest]] = [arr[largest], arr[i]]; [arr[i], arr[largest]] = [arr[largest], arr[i]];
animationSteps.push({ animationSteps.push({
array: [...arr], array: [...originalArray],
line: 33, line: 33,
description: `Recursively heapifying the affected subtree rooted at index ${largest}`, description: `Recursively heapifying the affected subtree rooted at index ${largest}`,
heapSize: n, heapSize: n,
@@ -411,7 +466,17 @@ function heapifyWithAnimation(arr, n, i, sortedIndices) {
sorted: sortedIndices ? [...sortedIndices] : [] sorted: sortedIndices ? [...sortedIndices] : []
}); });
heapifyWithAnimation(arr, n, largest, sortedIndices); heapifyWithAnimation(arr, n, largest, sortedIndices, originalArray);
} else {
// add explanation when no swap is needed
animationSteps.push({
array: [...originalArray],
line: 30,
description: `No swap needed: Element at index ${i} (${arr[i]}) is already in correct position for max heap`,
heapSize: n,
comparing: [i],
sorted: sortedIndices ? [...sortedIndices] : []
});
} }
} }
@@ -419,7 +484,7 @@ function nextStep() {
if (currentStep < animationSteps.length - 1) { if (currentStep < animationSteps.length - 1) {
currentStep++; currentStep++;
// update the array to current state // always use the original array for display
if (animationSteps[currentStep] && animationSteps[currentStep].array) { if (animationSteps[currentStep] && animationSteps[currentStep].array) {
array = [...animationSteps[currentStep].array]; array = [...animationSteps[currentStep].array];
} }