3.6.8 · D3Sorting & Searching

Worked examples — Bucket sort — uniform distributions

2,102 words10 min readBack to topic

This page drills the parent topic through every case class bucket sort can throw at you. We start by mapping the whole terrain, then walk one fully-worked example per cell.


The scenario matrix

Bucket sort has a small number of "shapes" the input can take. Every shape stresses a different part of the algorithm. Here is the full list — every later example is tagged with the cell it covers.

# Cell class What it stresses Example
A Typical uniform input in the normal happy path, Ex 1
B Boundary value or the out-of-range index bug Ex 2
C Zero / empty buckets reading empty slots, degenerate Ex 3
D Clumped / skewed input (worst case) all-in-one-bucket, Ex 4
E Rescaled range the normalize-first step Ex 5
F Cost accounting via the probability analysis, numbers Ex 6
G Negative + fractional real-world values mapping messy units to Ex 7
H Exam twist — duplicates & stability ties inside one bucket Ex 8
I Limiting behaviour and huge degenerate small case + trend Ex 9

Nine cells, nine examples. Let's cover them all.


Ex 1 — Cell A: the typical uniform run

Steps.

  1. Compute each index . Why this step? The index formula turns a value into an address — the whole reason bucket sort skips comparisons.

    • ; ; ;
    • ; ; ;
  2. Drop into buckets. Why this step? This is the "Scatter" S — grouping without ordering.

  3. Sort each non-empty bucket (only have items; both already ascending). Why this step? Buckets are tiny, so insertion sort is essentially free.

  4. Concatenate left to right, skipping empties:

Figure — Bucket sort — uniform distributions

Verify: landed in bucket 4 (forecast). Buckets 5 and 6 are empty — 2 empty buckets. Output is strictly increasing and is a permutation of the input. ✅


Ex 2 — Cell B: the boundary value

Steps.

  1. Compute naive indices. , , . Why this step? To expose the failure at the closed endpoint.

  2. Notice the crash. Valid indices are . Index is out of rangebuckets[3] throws. Why this step? This is exactly the third [!mistake] in the parent note, made concrete.

  3. Apply the clamp fix: idx = min(int(n*x), n-1). Why this step? It folds the single boundary point back into the top bucket without disturbing any interior value. Now .

  4. Re-bucket & concatenate: .

Verify: Naive index for is 3, which is invalid (). Clamped index is 2. Sorted output [0.2, 0.5, 1.0] is correct. ✅


Ex 3 — Cell C: mostly-empty (degenerate sparse) input

Steps.

  1. Indices: , . Why this step? Small inputs cluster into low buckets, leaving many empty — the sparse degenerate shape.

  2. Buckets: . Why this step? Shows the concatenation loop must gracefully skip 4 empty lists.

  3. Concatenate: . The empties contribute nothing.

Verify: 2 non-empty buckets (), 4 empty. Output [0.11, 0.19] sorted. ✅


Ex 4 — Cell D: the worst case (everything clumps)

Steps.

  1. Indices: , , , , . Why this step? All values live in , which is the single range mapping to bucket 4.

  2. All five land in : , every other bucket empty. Why this step? This is the definition of the worst case — one bucket holds all items.

  3. Cost of sorting : insertion sort on items costs comparisons in the worst case. With bucket size , this is . Why this step? It shows the average-case proof collapses when the uniform assumption is violated.

  4. Concatenate (only contributes): .

Figure — Bucket sort — uniform distributions

Verify: All 5 values in bucket 4; worst-case comparisons (insertion sort), so growth. Output [0.90, 0.91, 0.93, 0.95, 0.99] correct. ✅


Ex 5 — Cell E: rescaled range

Steps.

  1. Normalize with , here , width . Why this step? Bucketing only knows ; we must squeeze the original units into it first, keeping slots equal-width in the real units (each bucket spans units).

  2. Compute:

  3. Buckets: — one each.

  4. Concatenate: .

Verify: bucket 2. Sorted output [12, 25, 30, 47]. Bucket spans are 10 units each. ✅


Ex 6 — Cell F: the cost analysis in numbers

Steps.

  1. Model. Each element lands in bucket with , independently, so . See Binomial distribution. Why this step? Uniform input ⇒ equal per-bucket chance ⇒ this exact distribution.

  2. Mean: . Why this step? Confirms the design goal: one item per bucket on average.

  3. Variance: . Why this step? The spread measures "clumping" — how far bucket loads wander from 1.

  4. Second moment via : Why this step? This matches the parent's — the constant that makes the algorithm linear.

  5. Total quadratic work: . Why this step? Total insertion-sort cost = linear, the punchline.

Verify: , , , and . ✅


Ex 7 — Cell G: real-world word problem (negative + fractional)

Steps.

  1. Set range: , width , so each bucket spans °C. Why this step? Negative values are no obstacle — normalization handles the shift automatically.

  2. Normalize & floor with :

  3. Buckets: .

  4. Concatenate: (°C).

Verify: bucket 1. Sorted [-8.0, -3.5, 4.5, 12.0, 19.5] °C. ✅


Ex 8 — Cell H: exam twist — duplicates & stability

Steps.

  1. Indices on the key: (three times), . Why this step? Equal keys ⇒ equal indices ⇒ same bucket. Ties are inevitable here.

  2. Bucket receives, in scatter order, . Why this step? The scatter loop appends in input order, preserving original sequence.

  3. Sort stably. A stable sort on equal keys keeps the existing order: . Why this step? Stability of the whole algorithm hinges on the per-bucket sort being stable.

  4. Concatenate: .

Recall When is bucket sort stable?

Only if each bucket's internal sort is stable and elements are appended in input order. Which per-bucket sort keeps ties in order? ::: A stable one (e.g. insertion sort or a stable merge).

Verify: All three records in bucket 1; tie order a,b,d preserved. Output tags in order: c,a,b,d. ✅


Ex 9 — Cell I: limiting behaviour ( and )

Steps.

  1. (a) Degenerate . Index . The lone bucket . Why this step? The smallest legal input must still behave — one bucket, one item, zero swaps.

  2. Sort & concatenate: a 1-element list is already sorted → output [0.7]. Why this step? Confirms the algorithm is a no-op on trivial input (no crash, no infinite loop).

  3. (b) Limit of : as , , so . Why this step? Shows the per-bucket quadratic work is bounded above by 2 forever — it never grows with , which is why the total stays .

  4. Bound sanity: for every , . Even the smallest gives . Why this step? Every case, from to , lives in — no scenario escapes linearity.

Verify: (a) index , output [0.7]. (b) ; at the value is ; bound holds. ✅



Connections