3.6.8 · D5Sorting & Searching
Question bank — Bucket sort — uniform distributions
True or false — justify
TF1. Bucket sort is always .
False. The is expected time under uniform input; adversarial or skewed data can dump every element into one bucket, giving .
TF2. Bucket sort violates the comparison-sort lower bound.
False. It doesn't violate it — it sidesteps it. The scatter step uses each value as an address (not a comparison), so the bound about comparison sorts simply doesn't apply.
TF3. If you use buckets for elements, each bucket must contain exactly one element.
False. On average one per bucket, but randomness clumps them: some buckets get 0, some get 2 or 3. That variance is exactly what the term measures ( = count in bucket ).
TF4. Bucket sort is a comparison sort inside each bucket.
True (partially). The scatter is not comparison-based, but the per-bucket sort (usually Insertion sort) does compare. Since each bucket is tiny, those comparisons cost each on average.
TF5. Bucket sort can be made stable.
True. If elements keep their insertion order within a bucket and each bucket uses a stable internal sort, equal keys preserve their original relative order.
TF6. Doubling the number of buckets always makes bucket sort faster.
False. Creating and concatenating buckets costs . Far more than buckets wastes time scanning empty ones; the sweet spot stays .
TF7. Bucket sort works on any list of real numbers without preprocessing.
False. You must know (or estimate) the value range to normalize into via ; otherwise you cannot compute a bucket index.
TF8. Because expected bucket size is constant, the worst individual bucket is also constant-sized.
False. Expected size is constant, but with random inputs the largest bucket grows slowly — — and with adversarial input it can be . "Expected" is not "maximum" (see WHY8 for why that particular growth rate).
TF9. Bucket sort and Counting sort are the same algorithm.
False, but related. Counting sort is bucket sort's special case where each bucket holds one integer value (bucket size 1), so no internal sort is needed at all.
Spot the error
SE1. "I'll set idx = int(n * x) and it handles every in ."
Error: when ,
int(n*1.0) — an index one past the last valid bucket (). Use half-open or clamp with min(idx, n-1).SE2. "The proof uses , so total work is ."
Error: in general. The missing variance term matters: , not (recall = count in bucket ).
SE3. "I'll bucket by instead of ."
Error: dividing by shrinks values toward , so every maps to bucket . You want to stretch the interval by (multiply), not compress it.
SE4. "Since bucket sort is , I'll always prefer it over quicksort."
Error: the needs a known, roughly uniform distribution. On unknown or skewed data a comparison sort's guaranteed is safer than bucket sort's worst case.
SE5. "I emptied each bucket with a selection sort — same regardless."
Error: any sort on a bucket of expected constant size costs expected. The choice of internal sort doesn't change the linear expected total; only the input distribution does.
SE6. "Uniform on means the sorted output is also uniform, so I can skip the internal sort."
Error: buckets fill uniformly in count, but the two or three values inside one bucket are still unordered. You must sort within each bucket before concatenating.
Why questions
WHY1. Why does uniform input specifically give (with = count in bucket )?
Uniformity makes each element land in bucket with equal probability ; over elements . Non-uniform input skews these probabilities.
WHY2. Why is modelled as and not something else?
Each of elements independently either lands in bucket (probability ) or not — that's exactly independent yes/no trials, the definition of a Binomial distribution.
WHY3. Why does the quadratic term stay linear overall?
Each is constant, and there are buckets, so . Constant-per-bucket times buckets is linear.
WHY4. Why use insertion sort inside buckets rather than quicksort?
Buckets are tiny (expected size ), and Insertion sort has minimal overhead and is fast on small, near-sorted lists — quicksort's recursion overhead would dominate at that scale.
WHY5. Why does bucket sort share its core idea with Hashing?
Both compute an address directly from the value (index vs. hash bucket) instead of comparing. The difference: sorting needs order-preserving buckets; hashing only needs collision management.
WHY6. Why can't we just use the bound to conclude bucket sort is impossible?
That bound counts only comparison operations in the decision-tree model. Bucket sort's scatter extracts information from the value itself, an operation outside that model, so the bound doesn't constrain it.
WHY7. Why choose about buckets rather than a fixed small number?
With buckets each holds items, pushing internal sort toward per bucket — growing with . Matching buckets to elements keeps each bucket .
WHY8. Why is the largest bucket rather than constant, if the average is ?
This is the classic "balls into bins" result. Let be a candidate bucket-size threshold — the size we ask whether any bucket exceeds. The chance any fixed bucket exceeds size is roughly , and with buckets the maximum settles where . Solving gives — small but growing, so the max isn't constant even though the mean is.
WHY9. Why do more than buckets add cost rather than remove it?
Bucket creation, iteration, and concatenation each touch every bucket once, so their cost is regardless of how many are empty. With buckets you already spend just scanning, which dominates the scatter — the extra empty buckets buy no fewer collisions once you are past one-per-element, only wasted passes and memory.
Edge cases
EC1. All inputs are identical (say all ).
They all map to the same bucket, which then holds items — internal sort becomes . This is the degenerate worst case even though the values are "nice".
EC2. The input list is empty ().
You create buckets and the loops never run; output is the empty list. No index is ever computed, so no division-by-zero or out-of-range issue arises.
EC3. A value sits exactly on a bucket boundary, e.g. with .
cleanly, because the floor sends boundary points to the upper bucket. Floating-point rounding of can rarely nudge it, so half-open intervals plus clamping stay safest.
EC4. Exactly one element ().
One bucket, one element, index ; internal sort is trivial and output equals input. The linear bound holds vacuously.
EC5. Inputs come from but you forget to normalize.
Values outside produce indices that are negative or — out-of-range crashes. Always apply first.
EC6. Negative values with a naive int(n*x).
A negative makes negative;
int truncates toward zero (giving ) while floors down (giving a negative index that wraps to the list's end in Python or crashes elsewhere). Normalizing by the true removes the sign before bucketing.EC7. Inputs are integers over a small known range, not floats.
Then you don't need floats or internal sorting — one bucket per integer value gives Counting sort, the size-1-bucket special case, at guaranteed .
EC8. The range is zero: (e.g. every input equals ).
The normalization divides by zero. Guard for it: if all values are identical, so the array is already sorted — return it directly (or drop everything into bucket ) instead of computing the index.
Recall One-line summary of every trap
Bucket sort's speed is a distribution promise, not a guarantee: uniform ⇒ expected ; clumped or unnormalized or boundary-abused ⇒ crashes or . Match buckets to elements, normalize the range (guarding ), and always sort within each bucket.
Connections
- Bucket sort — uniform distributions (index 3.6.8) — the parent topic these traps target.
- Counting sort — the size-1-bucket edge case (EC7).
- Insertion sort — the per-bucket sort questioned in WHY4.
- Binomial distribution — underlies WHY2/WHY3.
- Comparison sort lower bound — the bound sidestepped in TF2/WHY6.
- Hashing — the value-as-address cousin of WHY5.