Discover how we implemented multiple algorithms with step-by-step recording, state persistence, and interactive history.
To allow users to navigate through time, we record a "snapshot" of the array and the visual state (active/swapping/sorted indices) at every meaningful point in the algorithm.
function addStep(snapshot) { steps.push({ array: [...snapshot.array], activeIndices: [...(snapshot.activeIndices || [])], swappingIndices: [...(snapshot.swappingIndices || [])], sortedIndices: [...(snapshot.sortedIndices || [])], description: snapshot.description || "" }); currentStep = steps.length - 1; updateStats(); }
We implemented six different algorithms. Here's a look at the Quick Sort partition implementation with visualization hooks:
async function partition(arr, low, high) { let pivot = arr[high]; addStep({ array: arr, activeIndices: [high], description: `Choosing pivot: ${pivot}` }); let i = (low - 1); for (let j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; [arr[i], arr[j]] = [arr[j], arr[i]]; addStep({ array: arr, swappingIndices: [i, j], description: "Swapping elements" }); } } // ... pivot placement logic }
The entire state, including all recorded steps and the current viewing position, is
saved to the browser's localStorage so you don't lose progress on refresh.
function saveToStorage() { localStorage.setItem('sorting_data', JSON.stringify({ array, steps, currentStep, algorithm: document.getElementById('algorithmSelect').value })); }
Bubble / Selection / Insertion
O(n²) - Simple but slow for large datasets. Good for small or nearly sorted arrays.
Merge / Quick Sort
O(n log n) - Highly efficient "Divide & Conquer" algorithms used in production environments.
Shell Sort
O(n log² n) - A gap-based improvement over Insertion Sort that bridges the gap between simple and advanced sorts.