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