Sorting Problem

Context: FIT1008_MOC, FIT2004_MOC · a Computational Problem · the three elementary sorts (Bubble/Selection/Insertion) + Stability & Incrementality · recursive sorts (Merge Sort, Quick Sort, Heapsort) referenced FIT2004 emphasis: every sort is graded on four axes — correctness (Invariant), time, auxiliary space, stability — and the suite splits into comparison-based (floored at ) vs non-comparison (Counting Sort, Radix Sort, which break the floor). W3 adds the engineering layer: how to force stability onto an unstable sort, and what sorting is actually for (§8).

Quick Revision

  • 🎯 Objective: rearrange orderable elements → non-decreasing ➔ correctness = permutation AND ordering (ordered-only misses drop/duplicate bugs).
  • 📦 Core Components: Bubble ➔ adaptive, swaps | Selection ➔ swaps, never adaptive | Insertion ➔ adaptive + online | non-comparison ➔ / .
  • ⚡ Key Constraint: all three elementary sorts are worst (arithmetic series ) ➔ discriminators are stability, swap count, adaptivity; the floor binds only algorithms that compare.

📝 Core

1. Comparison-Based vs Non-Comparison

  • Comparison-based ➔ the only access to keys is “is ?” — bubble, insertion, selection, Merge Sort, Quick Sort, Heapsort.
  • The floor ➔ every comparison-based sort is ⟹ sorts are provably optimal within that class.
  • Non-comparison ➔ Counting Sort and Radix Sort use the key as an array index, never comparing two items ⟹ the floor does not apply, at the cost of demanding bounded integer keys. The bound is escaped by narrowing the problem, not by beating it.
  • Selection rule ➔ bounded integer keys with range ⟹ Counting Sort; decomposable into narrow columns ⟹ Radix Sort; anything else ⟹ a comparison sort.

2. Bubble Sort

  • Mechanism ➔ walk L→R, swap each ➔ largest bubbles to the final tail.
  • Adaptivity ➔ BubbleSort II swapped flag ➔ best on sorted input.
  • Cost profile ➔ strict > ⟹ stable; up to swaps (one per inversion).

3. Selection Sort

  • Mechanism ➔ scan suffix for min ➔ exactly one swap/pass to leftmost unsorted ⟹ swaps (wins when writes are costly: flash, big records).
  • No best case ➔ the minimum must be located in full every pass ⟹ best avg worst ; unstable, because the long-distance swap can throw an equal key backwards ([4a,2,3,4b,1] → [1,2,3,4b,4a]).
  • Correctness ➔ two-clause prefix invariant + both counters increment ➔ Invariant.

4. Insertion Sort

  • Mechanism ➔ sorted prefix; shift larger elements right, drop temp into the gap.
  • Adaptive + online ➔ best (sorted input ⟹ the inner while never fires) ➔ absorbs a new last element in one pass.
  • Stability from shifting ➔ strict > means equal keys are never swapped past each other; shifting rather than swapping is what preserves order ➔ basis of [[Sorted List (ADT)|sorted-list add]].

5. Stability (Property)

  • Definition ➔ equal keys keep input order; observable only when sorting by key, and free/unobservable with distinct keys.
  • When it matters ➔ multi-pass sorting on several keys (sort by name, then by department, names stay ordered within each department) and any Radix Sort subsort.
  • Mechanism heuristic ➔ shifting is stable, long-distance swapping is not. Bubble/insertion/merge move items past adjacent or ordered positions; selection/heap/quicksort throw an item across the array and can hurdle an equal key. > vs >= is a one-character stability break.
  • Engineering fix A — tuple the index in ➔ compare on so ties break by original position; blocked when the container cannot hold tuples.
  • Engineering fix B — a parallel index list ➔ keep index_list alongside the data, consult it only when list[a] == list[b], applying every swap to both lists.
  • Time is UNCHANGED by either fix ➔ when the index list is never read; when equal, the tie-break compares two integers in ⟹ no factor added to any bound.
  • Space grows by one class at most ➔ selection sort goes from auxiliary to ; total space was already ⟹ the total bound does not move, only the in-place claim is lost.

6. Incrementality (Property)

  • Definition ➔ small input change ➔ rework (sorting’s online analogue) ➔ Online Algorithm.
  • Insertion yes / Selection no ➔ append-to-back needs one pass; a “final” prefix blocks latecomers. For frequent updates, graduate to a balanced Binary Tree/Heap (/update).

7. The Cost Terms Everyone Drops

  • Comparisons are not ➔ if comparing costs (words letter-by-letter, tuples field-by-field), every bound gains a factor: elementary sorts , Merge Sort · state or declare it constant. Input space follows: strings of length occupy .
  • Why an integer comparison IS ➔ a fixed-width machine word compares in one hardware instruction; a -character string must be walked. The asymmetry is architectural — the item type, not the algorithm, decides whether can be dropped.
  • Comparisons swaps, always ➔ no algorithm swaps a pair it never compared ⟹ use it as a self-check on a derived answer.
  • The recursion stack is auxiliary space ➔ levels of frames cost , and if each frame stores words ⟹ recursive sorts are not in-place even when they never allocate scratch. An iterative rewrite is the standard route to auxiliary — which is why “in-place?” and “recursive?” are nearly the same question.
  • Three auxiliary-space classes, three causes ➔ ⟸ iterative, swaps only (elementary sorts, Heapsort) · ⟸ a balanced recursion’s frame chain (Merge Sort’s stack, Quick Sort recursing smaller-first) · ⟸ a scratch array (Merge Sort’s buffer) or a degenerate recursion (Quick Sort’s worst-case stack). Naming the cause earns the mark.
  • Best worst is a diagnostic, not a coincidence ➔ the cases collapse exactly when (1) there is no early termination path and (2) the item values cannot change control flow. Selection sort and Merge Sort satisfy both; bubble (swapped flag) and insertion (inner while) violate (1), Quick Sort violates (2) ➔ Big-O Notation.

8. What Sorting Is FOR

  • Sorting is rarely the goal ➔ it is the preprocessing that makes a later pass linear; if the follow-up is not cheaper, the sort was not worth it.
  • Grouping ➔ equal keys become contiguous, so counting occurrences, finding the mode, or aggregating by key collapses to one sequential scan.
  • Deduplication ➔ duplicates are adjacent after sorting, so two-pointer compaction removes them in ; deleting in place by shifting the tail costs per removal, overall.
  • An “in-place” requirement PICKS THE SORT ➔ the compaction is already auxiliary, so the sort is the only term that can break the budget: Merge Sort spends on scratch and Quick Sort on stack ⟹ Heapsort is the only valid choice, the sole sort with auxiliary. Naming the sort is the marked step, not the two-pointer loop.
  • Why not a hash set or BST ➔ both dedup in expected / and preserve input order, but cost auxiliary ⟹ disqualified the moment “in-place” appears. Reach for them when order preservation outweighs space.
  • Enabling access ➔ sortedness is the precondition of Binary Search and of range reporting in ➔ Output-Sensitive Complexity.
  • Order statistics ➔ sorting answers every rank at once; for one rank, Quickselect does it in and sorting is over-solving.
  • The amortisation rule ➔ sort once at and every subsequent query is cheap; sort per query and the preprocessing is paid again each time.

⚙️ Core Implementation

🔹 Bubble Sort (II, adaptive)

🔹 Selection Sort (min swaps)

🔹 Insertion Sort (adaptive, online)

🔹 Two-pointer deduplication (the payoff of sorting)

⚖️ Core Decision Matrix

(Best / Average / Worst time, auxiliary space, stability, in-place. comparison cost applies to every comparison-based row.)

AlgorithmBestAverageWorstAuxiliary spaceStableIn-placeDistinctive trait
Bubble Sort (II)YesYesadaptive; swaps
Selection SortNoYesonly swaps
Insertion SortYesYesadaptive and online
HeapsortNoYesin-place and guaranteed
Merge Sort scratch stackYesNoguaranteed, stable
Quick Sort — fixable to stackDependsNofast in practice; pivot-sensitive
Counting Sort · stableengineeredNono comparisons; key range
Radix SortrequiredNo stable counting passes, LSD first

When It Flips: choose an sort when is small (low overhead), nearly-sorted (insertion → ), or writes dominate (selection's swaps). Choose a non-comparison sort only for bounded integer keys: Counting Sort while , Radix Sort while . Otherwise the floor makes Merge Sort/Heapsort optimal — merge for stability, heap for auxiliary.

📊 Exam Execution Trace

Manual Execution Trace

Insertion Sort on [5, 2, 4, 1]:

Step / StateTrigger OpmarktempShiftsArray Payload
0 (Init)init[5, 2, 4, 1]
1insert125→[2, 5, 4, 1]
2insert245→[2, 4, 5, 1]
3insert315,4,2→[1, 2, 4, 5]

Applied Exercise

Problem: Derive the worst-case bound of the elementary sorts on reverse-sorted input, then re-quote it when each comparison costs .

Final Extracted Output: worst case for bubble/selection/insertion, or with non-constant comparison cost; bubble & insertion reach best via their short-circuits, selection has no such path.

🧠 Active Recall