skip to content

questions

4

Why can bucket sort degrade to O(n^2) on power-law data, and what governs the degraded bound?

level: middleimportance: must knowfreq 55%

answer

  1. which phase is the only data-dependent one
  2. picture equal-width buckets over money amounts
  3. one bucket holds nearly all n records
  4. sum of squared bucket sizes, at its maximum
  5. equal depth, not equal width, fixes it

basics

~20 s

Skewed data crowds most keys into one bucket, so the per-bucket sort runs on nearly all n elements and dominates. The degraded bound is whatever that inner sort costs: quadratic with insertion sort, O(n log n) otherwise.

solid answer

~50 s

Bucket sort's linear expectation assumes the keys spread across buckets. Transaction amounts follow a power law — a huge mass of small payments, a thin tail of large ones — so equal-width buckets over the amount range leave the lowest bucket holding almost every record and the rest empty. Scatter and gather stay O(n), but phase two now sorts a bucket of size Θ(n), and that cost *is* the algorithm's cost: with the classic insertion sort inside, O(n²) on a report advertised as linear. An O(m log m) inner sort caps the worst case at O(n log n) — but then you have spent a pass and O(n + k) memory to land where a plain comparison sort already was. The real fix is to change the boundaries: derive them from sample quantiles so buckets get equal *depth*, not equal width, or transform the key onto a scale where the data spreads.

go deeper

for a junior

Know that bucket sort's speed depends on keys spreading out, and that heavily skewed data piles most keys into one bucket. Being able to name that failure, even without the formal bound, already puts you ahead.

for a middle

Explain precisely which phase degrades and why: scatter and gather stay linear, the per-bucket sort on a bucket of size n becomes the whole cost, and the resulting bound is whatever that inner sort costs.

for a senior

Show the judgment: name real heavy-tailed data you would refuse to bucket-sort, propose quantile-derived boundaries or a monotone key transform, and explain what a bounded fallback buys you in an on-call sense.

for a principal

Frame it as risk. A conditional bound in shared code is a latent incident when the data drifts; be ready to argue when a measured constant-factor win justifies owning that risk, and what monitoring makes it acceptable.

### The setup A payments report has to sort a day's transaction amounts. Amounts are known to lie between zero and some ceiling, so an engineer reaches for bucket sort: known range, linear expected time, obviously the right tool. Then the report that ran in seconds on staging data takes minutes in production. The difference is the distribution. Money is a textbook power law: overwhelmingly many small amounts, a thin tail of very large ones. Cut `k` equal-width buckets across the range and the lowest bucket owns the coffee-sized payments — which is nearly every row — while the buckets covering the top of the range hold a handful of records each, or none. ### Where the cost actually lands Walk the phases with skewed input: - **Scatter**: still O(n). One index computation per key; skew does not slow it down at all. - **Gather**: still O(n + k). Concatenating buckets is oblivious to how full they are. - **Sort each bucket**: this is the only data-dependent phase, and now one bucket holds Θ(n) keys. So the algorithm's cost collapses to the cost of the inner sort on the biggest bucket. Formally, the inner work is proportional to the sum over buckets of the inner sort's cost at that bucket's size; with a quadratic inner sort that sum is proportional to the **sum of squared bucket sizes**, which is minimised when the sizes are equal and maximised when one bucket holds everything. Uniform spread gives Θ(n); total concentration gives Θ(n²). ### The bound depends on the inner sort — say so "Bucket sort's worst case is O(n²)" is only true for the textbook formulation with insertion sort inside. State the dependency: | Inner sort | Worst-case total | Practical note | |---|---|---| | Insertion sort | O(n²) | Fastest when buckets really are tiny; catastrophic when one is not | | Any O(m log m) comparison sort | O(n log n) | Safe ceiling, but you have spent a pass and O(n + k) memory to match what a plain comparison sort gives you | | Recursive bucket sort on oversized buckets | Depends on whether the sub-range spreads | Helps for mild skew; a mass of *identical* keys never splits, no matter how many times you recurse | That last row is worth internalising. Re-bucketing an overfull bucket over its narrower sub-range fixes local clumping, but if ten million records all carry exactly the same amount, no partition of the value range will ever separate them — the only escape is to detect the duplicate run and stop. ### The two real fixes **Equal depth instead of equal width.** Sample the data, compute quantiles, and use those as bucket boundaries. Now each bucket is expected to receive about the same *number* of keys regardless of the shape of the distribution. This is a sampling pass plus a search per key to find the right boundary, and it is the idea behind sample-based partitioning sorts generally. It costs more per key than a division, and it assumes the sample represents the data. **Transform the key.** Money spans orders of magnitude, so bucket on a logarithmic scale, or on the digit-count of the amount. Any *monotone* transform preserves correctness of the gather while re-spreading the data. Non-monotone transforms silently produce unsorted output, so this is a place to be careful. A third answer is entirely legitimate in an interview: **refuse**. If you cannot characterise the distribution, cannot guarantee it stays that way, and cannot bound the largest bucket, then a sort whose bound is conditional is a latent incident. A well-implemented general-purpose sort gives O(n log n) on every input including the adversarial one, sorts in place or near it, and needs no assumptions to defend in review. ### The misconception this question aims at The wrong answer is "bucket sort is O(n)" said flatly, and its cousin "the worst case never happens with real data". Real data is exactly where it happens: money, city populations, file sizes, request latencies, word frequencies and follower counts are all heavy-tailed. Uniformity is the special case, not the default. A candidate who can name the mechanism — one bucket takes Θ(n), the inner sort's cost becomes the total — and then name the boundary fix has answered the question completely.

  • If you replace the per-bucket insertion sort with an O(m log m) sort, what is the worst case then?
    O(n log n): even if one bucket takes all n keys, sorting it costs O(n log n), and the scatter and gather are linear. That caps the damage — but it also means you have spent an extra pass and O(n + k) memory to land exactly where a plain comparison sort already sits, with no asymptotic win left. It is a safety net, not a speedup.
  • How would you keep bucket sort fast on money-like data without pretending it is uniform?
    Two options. Derive bucket boundaries from a sample's quantiles so each bucket receives roughly equal *counts* rather than equal ranges of value. Or apply a monotone transform — a logarithmic scale suits amounts spanning orders of magnitude — so the transformed keys spread evenly across equal-width buckets. Both cost a sampling or transform pass, and both assume the sampled shape holds for the full data.
  • Does recursively bucketing an oversized bucket always rescue the bound?
    No. Recursion re-spreads keys that merely clumped within a sub-range, and for mildly skewed data it works well. But a bucket full of *identical* keys can never be split — every recursion maps them to the same slot and recurses forever on the same set. Any recursive variant needs a duplicate check or a depth limit that falls back to a comparison sort.

saying these in an interview costs you the question

  • Says the worst case is theoretical and real data is uniform
  • Claims skew slows the scatter or gather phases
  • States O(n^2) worst case without naming the inner sort
  • Proposes more buckets as the fix for concentrated data
  • Thinks recursing on a full bucket always splits it

context

open as a page

What are bucket sort's three phases, and what must be true of the data for it to run in linear time?

level: juniorimportance: should knowfreq 50%

basics

~20 s

Bucket sort scatters keys into range-partitioned buckets by value, sorts each bucket with a simple sort, then concatenates the buckets in order. Expected linear time holds only when the keys spread evenly, leaving every bucket tiny.

open as a page

Counting, radix and bucket sort each demand a different precondition — what are the three?

level: middleimportance: should knowfreq 40%

basics

~20 s

Counting sort needs a small discrete key range to index a tally. Radix sort needs keys that split into a bounded number of digits. Bucket sort needs a known range plus a benign distribution over it.

open as a page

Before trusting bucket sort on a billion GPS longitudes claimed uniform, what do you verify?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Measure the distribution yourself: histogram a large sample at the intended bucket resolution and check the largest bucket, not the average. Then check who controls the keys, whether the shape drifts, and what the bucket count costs in memory.

open as a page