EECS 281 · FIELD NOTESSorting lectures 08—12 · learn by watching values move

Merge sort · watch each call

Comparisons 0 · Copies 0
a · the original array
↓ copy selected values into c; copy the completed range back into a ↑
c · temporary vector for this pair only
Left groupRight groupSorted output
0%

Drag to revisit any call, return, or copy. Play runs the whole example.

More explanation, runtime, and lecture notes

Lecture 12 · your slide code

Choose a version. Read the highlighted line, then press Next to see what it does.

Top-down sorts the left half, then the right half, then merges them. A one-item group returns immediately.

Understand this step

This call’s job
Next

    Read the literal code operation

    A copied number stays in a. The faded tile means “already read.” After this pair is merged, copy(begin(c), end(c), &a[left]) copies it back into the same part of a. The next call gets a new c.

    Green = executing line. Orange = a parent waiting for its call to return. The same function code is reused by many separate frames.

    This is the slide code, with spacing restored. The green bar marks the active driver line. While merge() runs, its calling line stays marked.

    Execution history and how frames work

    Each frame keeps its own local variables and return address. All calls use the same array a; recursion does not copy the whole array into each frame. Only merge() creates a temporary c.

    Execution order · most recent events

        Begin with two numbers to see one complete call-and-return story. Then choose the slide’s eight-number example. The C++ stays the same.

        Playback, examples, and pass shortcuts
        Why all these calls still give Θ(n log n) time

        Separate execution from cost. The stack shows which call runs next. Running time counts the work performed by all those calls, especially the items copied during merges.

        Merge-sort levelCompleted mergesItems handled

        Why not n²? A level has many calls, but their disjoint ranges together contain only n items. You do not merge all n items in every small call.

        Why log n levels? Halving 8 takes 8 → 4 → 2 → 1: three splits. There are three merge levels on the way back up. Generally T(n) = 2T(n/2) + Θ(n), for equal halves.

        Calls and memory: eight items make 15 merge_sort calls and 7 merge calls. Those 22 calls are not all on the stack at once: this example needs at most 4 active frames including the helper. Recursive stack depth is O(log n); the largest temporary c uses O(n) space. Total auxiliary space is O(n).

        The groups you have finished

        Every outlined group is sorted internally. Separate groups can still be out of order with one another.

        What each variable means
        size
        Size of one input group in merge_sortBU. It doubles after the entire pass: 1 → 2 → 4 → 8.
        Driver i
        The beginning of a pair. i += 2 * size advances past both input groups. This variable belongs to merge_sortBU.
        left, mid, right
        Inside merge, the left group is [left, mid); the right group is [mid, right). The ending index is excluded: [0, 2) uses slots 0 and 1.
        Helper i
        A new local variable inside merge. It reads the next left value; i == mid means the left group is empty.
        Helper j
        Reads the next right value; j == right means the right group is empty.
        Helper k
        Writes into local vector c. It starts at 0 for EVERY call. The for loop increases it after each assignment.
        Helper n
        right - left: number of items in THIS PAIR. It is not always the size of the whole array.
        ?: and ++
        condition ? X : Y chooses X when true and Y when false. In a[i++], use the old i to read the value, then increase i. The separate ++k advances the output slot.
        If you compile the printed slide code

        The slide uses Item as a placeholder type. For this integer example, define using Item = int; and include vector and algorithm with the appropriate std names. In the helper, spell the declaration size_t i = left, j = mid, k = 0;: its printed multi-variable auto declaration mixes size_t initializers with the int literal 0. The animation preserves the printed notation and follows its intended index operations.

        Explain each line of the top-down slide code
        1. Function header: sort only the range [left, right), not necessarily the whole array.
        2. Base case: left + 1 >= right means this piece has zero or one item. It needs no sorting.
        3. Return: stop this call and resume its parent. Return does not stop all recursive calls.
        4. Find mid: split the current range in half. Integer division rounds down; finding mid does not move numbers.
        5. Sort left: run the same function on [left, mid). The parent waits until that complete call returns.
        6. Sort right: after the left half returns sorted, run the function on [mid, right).
        7. Merge: both halves are now sorted. The slide 11 helper combines them into one sorted range.
        8. Closing brace: this call is finished. Its parent can continue. When the original call returns, the whole array is sorted.

        Why recursion works: a one-item range is sorted already. If both smaller halves return sorted, merging them gives a sorted larger range. Repeating this reasoning reaches the original full array.

        Cost: there are Θ(log n) levels, with Θ(n) total merge work per level: Θ(n log n) time. The temporary vectors need O(n) peak space, with O(log n) additional call-stack depth.

        Original lecture deck and topic map

        This is Lecture 12: Merge Sort, 18 slides. It is one lecture, not the entire EECS 281 course. The source is the actual saved deck; the .txt file is only a text extraction.

        Open the original 18-slide PDF · Open the PowerPoint

        • 1: split, sort each half, merge the halves.
        • 2 and 17: links to recorded videos; videos are separate from the static slides.
        • 3–4: how combining sorted groups differs from quicksort partitioning.
        • 5: the eight-item split-and-merge example used here.
        • 6: external sorting and extra memory.
        • 7: ternary operator and post-increment.
        • 8–9: mergeAB, two separate input arrays, and an example trace.
        • 10–11: the recursive driver and shared merge helper, used by this stack lesson.
        • 12–13: stability, sequential access, linked lists, and time and memory costs.
        • 14–15: bottom-up loops and their example, used by the other version.
        • 16: a frequency-finding interview question.
        • 18: self-study questions on linked lists, in-place merging, stability, and best-case time.

        The interactive execution follows slides 10–11 and 14–15. The stack cards and live cost table are added teaching aids; they are not diagrams copied from the lecture.

        Visualization controls inspired by Coddy’s merge-sort visualizer. This lesson keeps numbered array boxes and the EECS 281 slide implementations.

        Other sorts · animations and full lecture code

        A visual guide · start with the moving pieces

        Sorting, from first move to finished row.

        Learn what the whole algorithm does, follow every check and move, and see why the final row is sorted. Start with Bubble sort, then compare the other methods using the same five numbers.

        If this is all new

        Go in lecture order. In the lab, press Step one time at a time. Orange values are being checked or moved; green values are settled. Use the quiz map below to see what each lecture contributes. Open a C++ example when the visual rule starts making sense.

        New: understand the slide’s bottom-up merge sort code ↓

        Start here · one complete sorting job

        Same goal. Different ways to get there.

        Every lesson starts with 3, 1, 5, 2, 4. We finish only when the entire row is 1, 2, 3, 4, 5. A single swap or pass is one part of that job.

        Before
        31524
        Goal
        12345

        Compare means ask which number is smaller. Swap means exchange two numbers. A pass means one trip through the relevant part of the row.

        1. Read the four steps.2. Watch the full run.3. Explain why it finishes.

        Continue to the other sorting lessons ↓

        Learn one rule at a time

        The main idea

        Read the whole algorithm below, then choose Teach the full run. Pause and use Step to examine any decision.

          What one round accomplishes:

          When the entire algorithm stops:

          Interactive example · all seven sorts

          Follow the complete run.

          One click shows one check or one move. The sentence below tells you what comes next.

          A comparison checks the numbers. A move slides the tiles. Replay move shows the same move again without advancing.

            working on thesein order so farchosen value
            Try the small check ↓

            A sorted prefix or run is not necessarily in its final global position. Temporary copies and merge buffers are shown explicitly above.

            Where the running time comes from

            Logarithmic: log₂(n) counts roughly how many times you can halve n before reaching one. For 8 items, that is 3 halvings: 8 → 4 → 2 → 1. Θ describes how work grows with input size; O gives an upper bound.

            Notation: n means the number of items. Linear work grows like n; quadratic work grows like n². “Worst case” means the most work the algorithm needs for inputs of that size.

            Extra memory and equal values

            Stable means equal keys keep their original order. If two records have key 2, record 2A stays before record 2B when it started that way. In place means the algorithm rearranges the original array with only constant extra storage; recursive stack space still needs to be counted.

            Connect this to the quiz

            Review every major checkpoint in this run

            Open the complete color-coded C++ for this algorithm →

            Your turn · no score

            Check one idea.

            You can retry or revisit any lesson. A useful goal is explaining a move in your own words.

            Your lecture notes, in course order

            Lectures 8–12, the quiz topic map, and color-coded C++ examples. Use these after trying the small lessons, or jump straight to a topic you need.

            Your Lab 05 quiz · what to study

            Elementary sorts alone won’t cover it.

            You need Lectures 8, 10, 11, and 12, plus the binary-search and set-operation ideas from Lecture 9. Give 10 and 11 the closest attention.

            08 · Heapsort

            Heap construction, in-place sorting, stability, worst-case time, and recognizing heap-sort snapshots.

            09 · Sorted ranges

            Binary search inside insertion sort, combining two ranges, and scanning sorted data with a few pointers.

            10 · Elementary

            Bubble, selection, insertion, comparisons versus moves, nearly sorted input, and intermediate snapshots.

            11 · Quicksort

            Valid partitions with equal keys, pivot choices, recursion, linked-list feasibility, and tracing the exact lecture partition code.

            12 · Merge sort

            Sorted runs, singly-linked lists, sequential access, stability, and extra memory.

            Counting sort: lower priority for this quiz’s listed questions. For the handwritten 0/1/2 problem, the single-pass and constant-memory restrictions point to three-way partitioning; ordinary counting sort does not meet those restrictions as written.

            Some mathematical expressions disappeared from the pasted quiz. The lecture mapping is clear; those missing expressions still matter when choosing exact multiple-choice options.

            Read the colors before the code.

            Each C++ example is expandable. Follow the comments to see why each step exists. The examples use zero-based indexes: the first item is at index 0.

            whilelanguage rule inttype of value swap()function call 0number // whyexplanation
            C++ symbols, in plain English
            a[i]
            The value at index i in the vector.
            i++ / ++i
            Increase i by one. --i decreases it.
            vector<int>& a
            Work on the caller’s vector directly, rather than making a copy.
            size_t
            An unsigned integer type used for sizes and indexes.
            [left, right)
            Include index left; stop before index right.
            swap(a[i], a[j])
            Exchange the two values.

            These function examples assume #include <vector>, #include <algorithm>, #include <iterator>, and using namespace std;.

            The lecture path

            Five lectures, one question: how do items reach their places?

            08 · HeapKeep biggest easy to reachHeapsort
            09 · Sorted dataUse order to search or combineBinary search · set operations
            10—12 · SortingCompare simple and fast methodsElementary · quick · merge
            Need speed? Divide and conquer.
            Need little memory? Sort in place.
            Few possible keys? Count them.
            Lecture 08 · Heaps and Heapsort

            Keep the biggest at the top.

            A heap is a tree-shaped way to organize an array. It does not fully sort values; it keeps enough order to make the largest easy to grab.

            First, picture the heap

            In a max heap, every parent is at least as large as its children. So the root is the maximum. The other values can be in many orders.

            Heapsort moves the root to the far right, shrinks the heap, then lets the new root sink until the parent-child rule is restored.

            Think: “Take the current biggest and park it at the end.” Repeat to fill the array from right to left.

            Heap property · parent ≥ child

            9
            78
            2534

            Stored level by level using the slides’ convention: root index 1; children of index k are 2*k and 2*k+1.

            C++ · build and repair a max heap

            Exact Lecture 8 code · slide 39, slide 21

            void heapsort(Item heap[], size_t n) {  heapify(heap, n);  for (size_t i = n; i >= 2; --i) {    swap(heap[i], heap[1]);    fixDown(heap, i - 1, 1);  } // for i} // heapsort() void fixDown(Item heap[], size_t heapsize, size_t k) {  while (2 * k <= heapsize) {    size_t j = 2 * k; // start with left child    if (j < heapsize && heap[j] < heap[j + 1]) ++j;    if (heap[k] >= heap[j]) break; // heap restored    swap(heap[k], heap[j]);    k = j; // move down  } // while} // fixDown()

            Worst-case time Θ(n log n) · extra space O(1) · not stable. This example uses zero-based indexing; the slides also show a one-based version.

            Lecture 09 · Ordered, Sorted, and Sets

            Sorted order becomes a tool.

            This lecture is about what you can do after sorting. Sorted ranges let you search and combine without checking every pair.

            Binary search throws half away

            To find 9 in [1, 3, 5, 7, 9, 11, 13], check the middle. The first middle is 7 at index 3. Since 9 is larger than 7, ignore that value and the left half. Check the middle of what remains, then narrow again.

            Each check halves the range. That’s why binary search takes O(log n), instead of looking at all n values.

            Three similar tools

            • binary_search: does the value exist?
            • lower_bound: first value ≥ target.
            • upper_bound: first value > target.

            Try it · search a sorted row

            A duplicate-key example

            In [1, 3, 3, 3, 7], searching for 3 gives lower_bound = index 1 and upper_bound = index 4. The range between them contains all three copies.

            Search one value

            Binary search needs sorted data and takes O(log n) checks.

            Combine sorted ranges

            Set operations walk both left to right, taking the smaller next value. Usually O(m+n).

            C++ · binary search, bounds, and a sorted union
            vector<int> a = {1, 3, 3, 3, 7};int target = 3; // These all require sorted input.bool exists = binary_search(a.begin(), a.end(), target);auto low = lower_bound(a.begin(), a.end(), target);  // index 1auto high = upper_bound(a.begin(), a.end(), target); // index 4 // Two sorted inputs can be merged into a sorted union.vector<int> b = {2, 3, 8};vector<int> result;set_union(a.begin(), a.end(), b.begin(), b.end(),          back_inserter(result)); // result uses extra storage. For an O(1)-memory display problem,// scan the sorted inputs and print results as they are found.
            Lecture 10 · Elementary Sorts

            Three simple rules for moving values.

            Bubble, selection, and insertion sort all use comparisons. They differ in what each pass accomplishes. Choose one and step through the same list below.

            Bubble: compare neighbors

            Look at adjacent values. If backward, swap them. In this course version, a small value bubbles left. An early-stop check lets already sorted input finish in one pass.

            Selection: find the next smallest

            Scan the unsorted part, remember its smallest value, then swap it into the next open position. It still scans sorted input, but makes only O(n) swaps.

            Insertion: tuck the next value in

            Treat the left side as sorted. Pick the next value and slide bigger values right until there’s a gap. Like arranging cards in your hand. Nearly sorted input needs little shifting.

            Same input · after the first pass

            start
            52413
            bubble
            15243
            select
            12453
            insert
            25413
            Bubble + insertion

            Stable, in-place, useful on nearly sorted data. Worst case Θ(n²).

            Selection

            Θ(n²) comparisons even on sorted input, but only O(n) swaps.

            C++ · bubble sort: compare neighbors

            Exact Lecture 10 code · slide 17

            void bubble(Item a[], size_t left, size_t right) {  for (auto i = left; i < right - 1; ++i) {    bool swapped = false;    for (auto j = right - 1; j > i; --j) {      if (a[j] < a[j - 1]) {        swapped = true;        swap(a[j - 1], a[j]);      } // if    } // for j    if (!swapped)      break;  } // for i} // bubble()

            Adaptive version: Θ(n) on already sorted input; Θ(n²) worst case.

            C++ · selection sort: remember the minimum

            Exact Lecture 10 code · slide 22

            void selection(Item a[], size_t left, size_t right) {  for (auto i = left; i < right - 1; ++i) {    auto minIndex = i;    for (auto j = i + 1; j < right; ++j)      if (a[j] < a[minIndex])        minIndex = j;    swap(a[i], a[minIndex]);  } // for} // selection()

            Θ(n²) comparisons in every case; at most n−1 swaps.

            C++ · insertion sort: hold, shift, insert

            Exact Lecture 10 code · slide 37

            void insertion(Item a[], size_t left, size_t right) {  for (auto i = left + 1; i < right; ++i) {    Item v = a[i]; auto j = i;    while ((j > left) && (v < a[j - 1])) {      a[j] = a[j - 1];      --j;    } // while    a[j] = v;  } // for i} // insertion()

            Adaptive: Θ(n) best case; Θ(n²) worst case. Stable.

            Counting sort: use keys as bucket labels

            The slide version sorts full Student records by their category key. First count each category. Next turn frequencies into starting offsets. Finally scan the original records in order and copy each into its next free result position. There are no pairwise key comparisons.

            For input [2, 1, 2, 0, 3, 2], the buckets below mean one zero, one one, three twos, and one three. Output becomes [0, 1, 2, 2, 2, 3].

            The key range must be manageable. This version needs both counts and a separate output vector, so it is not the single-pass, constant-memory handwritten solution.

            Count by key

            key 01
            key 11
            key 23
            key 31

            These are pass 1 frequencies. Pass 2 changes them to starting offsets [0, 1, 2, 5]. Pass 3 copies original records into those category blocks.

            C++ · stable counting sort of Student records

            Exact Lecture 10 code · slide 56

            void counting_sort(vector<Student> &students) {  vector<Student> result(students.size());  vector<size_t> counts(CLASSES);  size_t temp, sum = 0;   for (auto &s : students)               // Pass 1: count each category    ++counts[s.classStanding()];  for (size_t i = 0; i < CLASSES; ++i) { // Pass 2: calculate start points    temp = counts[i];    counts[i] = sum;    sum += temp;  } // for i  for (auto &s : students) {             // Pass 3: sort    result[counts[s.classStanding()]] = s;    ++counts[s.classStanding()];  } // for  swap(students, result);} // counting_sort()

            O(n+k) time and space, where k is the number of possible keys. For stable sorting of records, use offsets and preserve the records when placing them into output.

            Other exact slide versions

            Slide 14 · basic bubble

            Exact slide 14 code. This version does not stop early.

            void bubble(Item a[], size_t left, size_t right) {  for (auto i = left; i < right - 1; ++i)    for (auto j = right - 1; j > i; --j)      if (a[j] < a[j - 1])        swap(a[j - 1], a[j]);} // bubble()
            Slide 24 · avoid self-swaps

            Exact slide 24 code. The added if skips a swap when minIndex already equals i.

            void selection(Item a[], size_t left, size_t right) {  for (auto i = left; i < right - 1; ++i) {    auto minIndex = i;    for (auto j = i + 1; j < right; ++j)      if (a[j] < a[minIndex])        minIndex = j;    if (minIndex != i)      swap(a[i], a[minIndex]);  } // for} // selection()
            Slide 31 · basic adjacent swaps

            Exact slide 31 code. The inner loop still visits every earlier neighbor.

            void insertion(Item a[], size_t left, size_t right) {  for (auto i = left + 1; i < right; ++i)    for (auto j = i; j > left; --j)      if (a[j] < a[j - 1])        swap(a[j - 1], a[j]);} // insertion()
            Slide 39 · sentinel version

            Exact slide 39 code. The minimum at a[left] stops the while loop, so it omits j > left.

            void insertion(Item a[], size_t left, size_t right) {  for (auto i = right - 1; i > left; --i) // find min item,    if (a[i] < a[i - 1])                  // put in a[left]      swap(a[i - 1], a[i]);               // as sentinel   for (auto i = left + 2; i < right; ++i) {    Item v = a[i]; auto j = i;            // v is new item    while (v < a[j - 1]) {                // v in wrong spot      a[j] = a[j - 1];                    // copy/overwrite      --j;    } // while    a[j] = v;  } // for i} // insertion()
            Lecture 11 · Quicksort

            Split around a pivot.

            Quicksort partitions the range: smaller values go left, larger values go right. Then it repeats on each side.

            A pivot makes a boundary

            In the slide 9 partition, values left of pivot 4 are strictly less than 4; values right of it are at least 4. Those sides aren’t sorted yet, but sorting each finishes the job.

            Balanced sides give Θ(n log n). If each pivot leaves one huge side and one tiny side, it can degrade to Θ(n²).

            Think: Quicksort arranges during the split. No separate merge at the end.

            Partition around pivot 4

            625143

            One valid partition:

            213456

            Groups are on the correct side; each group still needs sorting.

            C++ · the exact partition policy quoted in your quiz

            Exact Lecture 11 code · slide 9

            size_t partition(Item a[], size_t left, size_t right) {  auto pivot = --right; // beware right == 0  while (true) {    while (a[left] < a[pivot])      ++left;    while (left < right && a[right - 1] >= a[pivot])      --right;    if (left >= right)      break;    swap(a[left], a[right - 1]);  } // while  swap(a[left], a[pivot]);  return left;} // partition()

            One partition call is O(n). It separates groups; it does not sort each group.

            C++ · recurse after partitioning

            Exact Lecture 11 code · slide 6

            void quicksort(Item a[], size_t left, size_t right) {  if (left + 1 >= right)    return;  auto pivot = partition(a, left, right);  quicksort(a, left, pivot);  quicksort(a, pivot + 1, right);} // quicksort()

            Average Θ(n log n), worst Θ(n²). Additional recursion stack: typically O(log n), potentially O(n) for this basic implementation.

            Lecture 12 · Merge Sort

            Sort halves, then weave them together.

            Merge sort divides the array until each piece has one item. Then it merges small sorted pieces into larger sorted pieces.

            The merge does the sorting

            Suppose sorted halves are [2, 5, 8] and [1, 4, 7]. Compare their front values, take the smaller one, and advance only that half.

            Each merge pass touches every item once. There are about log₂(n) levels, so time is Θ(n log n), even if input is already sorted or reversed.

            Think: Quicksort splits values into sides. Merge sort splits by position, then sorts while merging.

            Merge two sorted halves

            258+147

            Take the smaller front each time:

            124578

            Result: [1, 2, 4, 5, 7, 8]

            C++ · exact merge_sort() and merge() from slides 10–11

            Exact Lecture 12 code · slide 10, slide 11

            void merge_sort(Item a[], size_t left, size_t right) {  if (left + 1 >= right) // base case: 0 or 1 item(s)    return;  auto mid = left + (right - left) / 2;  merge_sort(a, left, mid);  // [left, mid)  merge_sort(a, mid, right); // [mid, right)  merge(a, left, mid, right);} // merge_sort() void merge(Item a[], size_t left, size_t mid, size_t right) {  auto n = right - left;  vector<Item> c(n);   for (auto i = left, j = mid, k = 0; k < n; ++k) {    if (i == mid)      c[k] = a[j++];    else if (j == right)      c[k] = a[i++];    else      c[k] = (a[i] <= a[j]) ? a[i++] : a[j++];  } // for   copy(begin(c), end(c), &a[left]);} // merge()

            Standard array version: Θ(n log n) time, O(n) auxiliary array. Equal keys keep their order because the left side wins ties.

            Connect the lectures · quiz reasoning

            The questions combine these ideas.

            Use the data structure, the memory limit, and the kind of work being counted to decide which algorithm fits.

            Finding a slot is different from making room.

            Binary search can find an insertion position in O(log n), but inserting into an array may still shift O(n) items. Across all insertions, the worst-case shifting work is Θ(n²).

            A linked list rewards sequential access.

            A merge can advance through list nodes without jumping to an arbitrary index. That makes merge sort a natural Θ(n log n) choice for linked lists. An array heap depends on fast parent/child indexing, which ordinary lists do not provide.

            Sorted data lets two pointers do the next job.

            For a closest-sum pair, sort first, then keep one pointer at each end. A sum that is too small means moving the left pointer right; a sum that is too large means moving the right pointer left. The scan is linear. Count the sorting cost too.

            If total extra space must be O(1), heapsort meets that array-sorting restriction. A basic recursive quicksort also needs stack space.

            “In either range, but not both” is symmetric difference.

            Sort both ranges, then compare their current items. Output the smaller unmatched item. Skip a match and advance both. Treat duplicate counts according to the question’s definition; set membership and multiset counts are different.

            A snapshot reveals the algorithm’s promise.

            Merge sort forms sorted runs of sizes 1, 2, 4, … in its bottom-up version. Selection settles a minimum on each pass. Insertion grows a sorted prefix. Bubble moves an extreme value across neighbors. Heapsort first forms a heap, then grows a sorted suffix.

            [a] [b] [c] [d] → [a b] [c d] → [a b c d]

            Stable means equal keys keep their order.

            Sorting [2A, 1, 2B] stably gives [1, 2A, 2B]. It preserves which equal-key record came first. Stability does not mean a runtime guarantee. Standard bubble, insertion, and merge sort are stable; standard selection, heap, and in-place quicksort are not.

            Pivot choice affects the split.

            Balanced partitions give about log n levels of linear partitioning work. Repeated 0-versus-(n−1) splits give quadratic work. Sorted input alone does not determine quicksort’s time; the pivot rule and partition behavior matter.

            For general partition questions, equal keys may appear on either side if no stricter rule is specified. When tracing supplied code, obey its exact < and >= conditions.

            Fast comparisons do not erase expensive moves.

            For comparison sorting, the best possible general worst-case growth is Ω(n log n) comparisons. Elementary selection sort makes Θ(n²) comparisons but only O(n) swaps. If copying large records dominates, that difference matters.

            Handwritten 0/1/2 task: understand the regions first

            Maintain four regions: zeros, ones, unknown values, twos. The scan pointer looks at the first unknown item. A 0 goes to the left region; a 2 goes to the right region; a 1 is already in its region. After swapping a 2 rightward, inspect the incoming value before advancing the scan.

            0s1sunknown2s

            This is the three-way partition idea. The quicksort trace earlier uses the separate two-way lecture implementation because that is the one quoted in the quiz.

            Memory hooks

            Heap: remove the biggest. Bubble: swap neighbors. Selection: find next smallest. Insertion: slide into sorted part. Quick: partition around a pivot. Merge: weave sorted halves. Binary search: halve a sorted range.

            Original lecture source files