This is the same TypeScript function that computes the visualization.
Bubble Sort has O(n) best-case and O(n²) average/worst-case work. This last-pivot Quick Sort averages O(n log n), but can take O(n²), including sorted or equal-valued input. Neither is always faster. Bubble Sort preserves equal-value order; this Quick Sort does not promise stability.
THE SIMPLE IDEA
Input → algorithm → result
INPUTUnsorted numbers
→
ONE FUNCTIONBubble Sort
→
OUTPUTAscending numbers
Keep the original list intact. Return ascending values, including duplicates. This promise stays the same for the entire lesson.
OPTIONAL · PUT IT INTO PRACTICETry the next requirement
Add Insertion Sort. Keep the promise.
A third algorithm is ready. Your task is to make it available without reopening Sorter. Choose the changes, then check that the replacement behaves as callers expect.
Inspect the supplied TypeScript implementation
It sorts a copy, preserves duplicates, and records its real operations. You do not need to learn the sorting loop to answer the questions.
import type { Item, SortEvent, SortRun } from "./sorting.ts";
import type { SortStrategy } from "./strategies.ts";
// Supplied for the transfer check; no changes to Sorter or SortStrategy.
export class InsertionSort implements SortStrategy {
sort(input: readonly number[]): SortRun {
const items: Item[] = input.map((value, id) => ({ value, id }));
const events: SortEvent[] = [];
const record = (
kind: "compare" | "swap" | "done",
indices: number[],
caption: string,
) => {
events.push({
kind,
anchor:
kind === "compare"
? "insertion-compare"
: kind === "swap"
? "insertion-swap"
: "insertion-done",
items: items.map((item) => ({ ...item })),
indices: [...indices],
settledFrom: kind === "done" ? 0 : items.length,
caption,
});
};
for (let i = 1; i < items.length; i++) {
for (let j = i; j > 0; j--) {
record(
"compare",
[j - 1, j],
"Compare neighbors in the growing sorted prefix.",
);
if (items[j - 1].value <= items[j].value) break;
[items[j - 1], items[j]] = [items[j], items[j - 1]];
record("swap", [j - 1, j], "Move the smaller value one place left.");
}
}
record(
"done",
[],
"Ascending order reached. The original input is unchanged.",
);
return {
input: [...input],
output: items.map((item) => item.value),
events,
};
}
}
Can you use Strategy in another setting?
Keep the idea, change the problem. Build a checkout with interchangeable shipping rules.