Fact-checked by Grok 2 weeks ago

Bucket sort

Bucket sort is a sorting algorithm that partitions an array of elements into several buckets, sorts the elements within each bucket individually (typically using insertion sort), and then concatenates the sorted buckets to produce the final sorted output. It is designed primarily for sorting real numbers that are uniformly and independently distributed over the interval [0, 1). The algorithm begins by creating n buckets, where n is the number of input elements, each corresponding to a subinterval of length 1/n within [0, 1). For each input number x, it computes the bucket index as floor(n * x) and places x into that bucket, ensuring that elements in earlier buckets are smaller than those in later ones. After distribution, each non-empty bucket is sorted using insertion sort, which is efficient for small lists, and the sorted contents of the buckets are then concatenated from left to right. Assuming uniform distribution, the expected number of elements per bucket follows a binomial distribution, leading to an expected running time of O(n) for n elements. However, in the worst case—such as when all elements fall into a single bucket—the time complexity is Θ(n²) due to the quadratic behavior of insertion sort on that bucket. Bucket sort requires O(n) extra space for the buckets and is a distribution-based method rather than a pure comparison sort, though the internal bucket sorting relies on comparisons. It is most efficient when the input meets the uniform distribution assumption and can be adapted for other ranges by scaling, but performs poorly on clustered or adversarial data.

Overview

Algorithm Description

Bucket sort is a distribution-based sorting algorithm that assumes the input elements are uniformly distributed over a known range, such as the interval [0, 1). The algorithm proceeds in four primary steps. First, an array of n empty buckets is created, where n is the number of elements to sort. Second, each input element x is distributed into a bucket by calculating its index as \lfloor n \cdot x \rfloor for values in [0, 1), or more generally \lfloor n \cdot \frac{x}{max} \rfloor when the range is [0, max]. Third, each non-empty bucket is sorted individually, often using an efficient algorithm like insertion sort suitable for small lists. Finally, the sorted buckets are concatenated in order to produce the fully sorted output array. Under the uniform distribution assumption, elements are evenly spread across the buckets, resulting in approximately one element per bucket on average and minimizing the work required for intra-bucket sorting. This approach is typically applied to floating-point numbers or scenarios where the input range is known and uniformity holds, enabling linear-time performance in expectation.

Key Assumptions and Prerequisites

Bucket sort relies on the assumption that the input elements are uniformly or nearly uniformly distributed across a known range to achieve balanced distribution into buckets, ensuring that each bucket receives approximately the same number of elements on average. This uniform distribution is crucial because it allows the algorithm to partition the data evenly, preventing any single bucket from becoming disproportionately large. A key prerequisite is the knowledge of the input's minimum and maximum values, which define the overall range and enable the determination of bucket boundaries. Without this range information, setting appropriate bucket intervals becomes impossible, rendering the algorithm ineffective for direct application. The algorithm is particularly suited for sorting real numbers within a bounded interval, such as [0, 1), where elements can be mapped to buckets based on their fractional values. For integer inputs, adaptations like counting sort may be more appropriate if the range is discrete and known, but bucket sort's flexibility with continuous values highlights its limitations when the range is unbounded or unknown, as dynamic range estimation would be required. Implementers need a basic understanding of array structures for storing buckets and familiarity with stable sorting methods, such as insertion sort, which is commonly used to sort elements within individual buckets. Non-uniform distributions can lead to skewed buckets, where most elements fall into one or a few buckets— for instance, all inputs concentrating in a single bucket—resulting in degraded performance as the sorting reduces to handling an unbalanced load.

Implementation

Pseudocode

The standard bucket sort algorithm distributes elements of an input array into buckets based on their values, sorts each bucket individually, and concatenates the results to produce a sorted output. This pseudocode assumes an input array A of n real numbers uniformly and independently distributed in the interval [0, 1), with the number of buckets k set to n.
BUCKET-SORT(A)
1  n ← length[A]
2  create n empty lists B[0], B[1], ..., B[n-1]
3  for i ← 0 to n-1 do
4      bucket_index ← floor(n * A[i])
5      insert A[i] at the end of list B[bucket_index]
6  for i ← 0 to n-1 do
7      sort list B[i] using insertion sort
8  concatenate lists B[0], B[1], ..., B[n-1] together in order (this is the output)
In the above pseudocode, the input is denoted by array A of size n, while B represents an array of n initially empty lists acting as buckets; the output is the concatenated sequence from the sorted buckets. The key distribution step (lines 3–5) computes the bucket index using the formula \lfloor n \cdot A \rfloor, which maps each element to one of the n equally sized subintervals of [0, 1) under the uniform distribution assumption. For inputs in a general range [0, \max_value), the bucket index formula generalizes to \lfloor n \cdot \key / \max_value \rfloor, where \key is the current element, ensuring even distribution across buckets when values are uniformly spread. The sorting step (lines 6–7) applies insertion sort to each bucket list B, as it performs efficiently on the small, expected sizes of these lists. Empty buckets are handled naturally in the sorting loop, requiring no special action since sorting an empty list incurs negligible cost. The final concatenation (line 8) merges the sorted buckets sequentially to form the overall sorted array. The buckets may alternatively be sorted recursively by invoking bucket sort on each non-empty B, though this variant demands provisions to terminate recursion for small or degenerate cases.

Worked Example

To illustrate the bucket sort algorithm, consider an unsorted array of seven floating-point numbers uniformly distributed in the range [0, 1): [0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21]. For this example, select 5 buckets, each spanning an equal interval of 0.2, determined by computing the bucket index as the floor of the element value multiplied by the number of buckets (i.e., index = ⌊value × 5⌋). The elements are distributed as follows:
Bucket IndexRangeElements Distributed
0[0.0, 0.2)0.17
1[0.2, 0.4)0.39, 0.26, 0.21
2[0.4, 0.6)(empty)
3[0.6, 0.8)0.78, 0.72
4[0.8, 1.0)0.94
Each non-empty bucket is then sorted using insertion sort. For bucket 1, insertion sort rearranges [0.39, 0.26, 0.21] by inserting 0.26 before 0.39 and then 0.21 before both, yielding [0.21, 0.26, 0.39]; the other buckets require minimal swaps or none. The sorted buckets are:
Bucket IndexSorted Elements
0[0.17]
1[0.21, 0.26, 0.39]
2(empty)
3[0.72, 0.78]
4[0.94]
Finally, concatenate the sorted buckets in order to produce the fully sorted array: [0.17, 0.21, 0.26, 0.39, 0.72, 0.78, 0.94]. In this case, the uniform distribution of inputs results in relatively balanced bucket sizes (most containing 1–3 elements), which supports the algorithm's efficiency under its key assumption.

Performance Analysis

Time Complexity

The time complexity of bucket sort depends on the distribution of input elements and the number of buckets k, assuming each bucket is sorted using an O(m^2) algorithm like insertion sort, where m is the number of elements in a bucket. In the worst case, all n elements fall into a single bucket, reducing the algorithm to sorting n elements with insertion sort, yielding O(n^2) time. This occurs when the input is non-uniform and clustered, such as all keys mapping to the same interval. The average case assumes a uniform distribution of n elements over the range [0, 1), with k buckets (typically k = n). The time is O(n + k), derived as follows: distributing elements into buckets takes O(n) time, concatenating sorted buckets takes O(n) time, and sorting within buckets totals O(n) expected time. More precisely, the expected time satisfies E[T(n)] = O(n) + \sum_{i=1}^k E[T(n_i)], where n_i is the number of elements in bucket i, and E[n_i^2] = 2 - 1/n \approx 2 under uniformity, so the sorting cost sums to O(n). With k = n, this simplifies to linear time overall. In the best case, each bucket contains at most one element (e.g., perfectly uniform with k \geq n), requiring no intra-bucket sorting beyond trivial checks, resulting in O(n) time dominated by distribution and concatenation. The choice of k influences performance; setting k \approx n optimizes the average case for uniform data by balancing distribution and sorting costs, as larger k increases concatenation overhead while smaller k risks uneven buckets.

Space Complexity

Bucket sort has an overall space complexity of O(n + k), where n is the number of input elements and k is the number of buckets used. This bound accounts for the input array itself, which requires O(n) space, along with the auxiliary structures needed for the algorithm. In the worst case, all n elements could be distributed across the k buckets, but the total allocation remains linear in n and k since k is typically chosen proportional to n for uniform distributions. The auxiliary space primarily arises from the bucket array, implemented as an array of k empty lists, which demands O(k) space for initialization, plus O(n) space to hold the elements once distributed, as each input element is appended to exactly one list. Concatenating the sorted buckets into the final output may require an additional O(n) temporary array if the implementation does not overwrite the input in place, though optimized versions can minimize this by reusing the original array where possible. Thus, the algorithm requires O(n + k) extra space beyond the input, making it unsuitable for memory-constrained environments without modifications. While an in-place variant of bucket sort is theoretically possible by carefully swapping elements within the input array to simulate buckets, standard implementations avoid this due to the complexity of managing bucket storage without auxiliary lists or arrays, opting instead for the straightforward O(n + k) auxiliary space. If bucket sort is implemented self-recursively—by applying the algorithm to sort each bucket rather than using a simpler method like insertion sort—the recursion depth in a balanced distribution would add O(\log n) stack space; however, this approach is typically avoided to eliminate such overhead and simplify the design.

Optimizations

Bucket Selection Strategies

In the standard formulation of bucket sort, the number of buckets k is chosen equal to the number of input elements n when the keys are uniformly and independently distributed real numbers in the interval [0, 1). This selection ensures that each bucket receives an expected constant number of elements (approximately 1 on average), allowing the subsequent sorting of individual buckets—typically using insertion sort—to take constant expected time per bucket, yielding an overall average-case time complexity of O(n). For integer keys within a known finite range [ \min, \max ], a range-based bucketing strategy sets k = \max - \min + 1, effectively reducing the algorithm to counting sort where each bucket corresponds to a specific value. However, when the range significantly exceeds n (e.g., sparse integers over a large domain), k is often capped at n or a smaller value to prevent prohibitive space usage while maintaining reasonable distribution. Dynamic sizing of buckets adjusts k based on the observed data range and input size to optimize performance; for instance, setting k \approx \sqrt{n} in certain scenarios balances the distribution phase with the intra-bucket sorting costs when using simple sorters like insertion sort. Empirical guidelines suggest selecting larger k to minimize the expected size of each bucket and thus reduce per-bucket sorting time, though this increases the overhead associated with bucket allocation and final concatenation. Key trade-offs in bucket selection include the risk of uneven distribution with too few buckets, which can concentrate many elements in one or few buckets and degrade performance to O(n^2) in the worst case, versus excessive space consumption and initialization costs with too many buckets (e.g., k \gg n), where most buckets remain empty.

Handling Edge Cases

Bucket sort assumes a uniform distribution of input elements to achieve optimal performance, but non-uniform inputs can lead to degenerate cases where most elements cluster into few buckets, causing unbalanced workloads and potentially degrading the average-case time complexity to O(n²). To mitigate this, a pre-scan can estimate the input distribution by sampling elements and constructing a histogram or cumulative distribution function (CDF), enabling adaptive bucketing that adjusts bucket boundaries to ensure roughly equal elements per bucket. For instance, probability distribution-based partitioning uses sampling (e.g., 40,000 samples for high-confidence estimation) to fit a CDF and assign elements to balanced buckets, improving partition balance by 10-30% even for skewed data while maintaining linear-time overhead. When the input range is unknown, bucket sort requires an initial pass to compute the minimum and maximum values, allowing the bucket index to be calculated as floor(n * (element - min) / (max - min + 1)) to distribute elements appropriately. If the range is extremely large or computation risks overflow (e.g., in integer arithmetic for very wide ranges), implementations should use 64-bit integers to avoid overflow. Duplicate elements are handled naturally in bucket sort, as they map to the same bucket and maintain their relative order if a stable sort like insertion sort is used within buckets; however, high duplication can unbalance buckets, exacerbating the non-uniform issue. To address potential unbalance from duplicates, especially for integer keys, counting sort can be applied within each bucket to process frequencies in linear time relative to the bucket size, avoiding quadratic degradation from insertion sort on large duplicate sets. For empty or single-element inputs, bucket sort trivially succeeds in O(n) time, as no distribution or intra-bucket sorting is needed beyond allocating empty buckets and returning the input unchanged. In implementations involving floating-point numbers, indexing can suffer from precision errors due to rounding in the bucket assignment formula, particularly when the range is narrow or elements are densely clustered; to prevent this, elements can be scaled to integers before mapping, or integer arithmetic can be enforced throughout to sidestep floating-point overflow and inexact representations.

Variants

Generic Bucket Sort

Generic bucket sort extends the standard bucket sort algorithm to accommodate arbitrary data types beyond numeric values by incorporating a user-defined bucketing function that maps each element to a specific bucket index. This mapping function can be a hash function, a key extraction method, or any deterministic procedure that distributes elements into a fixed number of buckets, allowing the algorithm to operate on diverse inputs such as strings, objects, or custom structures without assuming a predefined numerical range. A key feature of generic bucket sort is the use of dynamic data structures like linked lists or queues for each bucket, which facilitate efficient insertions and preserve the relative order of elements for stability when combined with a stable sorting subroutine within each bucket. After distribution, the contents of each bucket are sorted individually using a stable algorithm, such as insertion sort, and the sorted buckets are then concatenated in order to produce the final sorted sequence. This approach mirrors hashing in its potential for collisions, where multiple elements may map to the same bucket, but relies on the subsequent sorting step rather than resolution techniques like chaining or open addressing. Common use cases include sorting strings by attributes like length or initial character, where the bucketing function assigns strings starting with 'A' to one bucket, 'B' to another, and so on, based on alphabetical position. For objects, such as sorting records by a field like employee ID or category, the function extracts and maps the relevant key to a bucket index, enabling efficient distribution for large datasets with heterogeneous elements. The pseudocode for generic bucket sort adapts the core distribution and collection steps to include a customizable bucketing function:
BUCKET_SORT(A, n, bucket_func, stable_sort)
    create n empty buckets B[0..n-1], each as a linked list
    for i = 0 to |A|-1 do
        bucket_index = bucket_func(A[i])  // maps element to [0, n-1]
        insert A[i] at the end of B[bucket_index]  // maintain stability
    output = empty array
    for i = 0 to n-1 do
        append stable_sort(B[i]) to output
    return output
Here, bucket_func is the user-provided mapping (e.g., hashing the first character of a string to its ASCII-based index modulo n), and stable_sort is a stable subroutine like insertion sort applied to each non-empty bucket. This adaptation ensures flexibility while preserving the algorithm's distribution-based efficiency.

ProxmapSort

ProxmapSort is a variant of bucket sort that employs a proximity mapping mechanism to partition and arrange elements into their approximate final sorted positions, enabling efficient linear-time performance for uniformly distributed inputs. Developed by Thomas A. Standish for use in data structures education and general-purpose sorting, it was first described in his 1995 textbook Data Structures, Algorithms, and Software Principles in C and later elaborated in a 2005 collaborative paper with Norman Jacobson to motivate computer science students. The algorithm is particularly suited for scenarios requiring order-preserving distributions, such as in vector spaces where maintaining element proximity is beneficial. The core mechanism of ProxmapSort involves defining buckets via a map key function that assigns each element to a bucket index, typically transforming the key into a value between 0 and 1 (e.g., using the fractional part for floating-point keys) before flooring to an integer index. A hit list array tallies the occupancy of each bucket, followed by the construction of a proximity map array that computes cumulative starting positions for each non-empty bucket's subarray in the output. Elements are then mapped to these proximate locations—close to their sorted order—using the proximity map, with empty buckets marked to avoid allocation overhead. Unlike uniform bucketing in generic bucket sort, this approach uses proximity regions implicitly defined by the map key, akin to Voronoi-like partitioning where elements are assigned to the nearest bucket center based on the key's value; for multidimensional data, the map key can incorporate a distance metric like Euclidean distance to project points into one-dimensional buckets while preserving spatial relationships. Within each bucket, insertion sort refines the order, ensuring overall sorted output. This process relies on parallel arrays (hit list, location indices, proximity map, and output) for O(1) access, eliminating linked lists. ProxmapSort offers advantages in handling clustered data distributions better than traditional uniform bucketing, as the customizable map key can group spatially or semantically similar elements into fewer, denser buckets, thereby reducing the incidence of empty buckets and minimizing overhead. In spatial contexts, such as geographic information systems, this leads to improved locality preservation, where nearby points in vector spaces remain proximate post-sorting, facilitating applications like nearest-neighbor queries. The algorithm requires a suitable distance metric embedded in the map key function to measure proximity effectively; for instance, in Euclidean spaces, the key might linearize coordinates via a space-filling curve to maintain clustering. Sorting within buckets further enhances locality by locally ordering elements without global disruptions. An example application is sorting points in a 2D plane by their coordinates for visualization or spatial indexing, where the map key divides the plane into proximity-based regions to cluster points efficiently before intra-bucket refinement. Overall, these features make ProxmapSort scalable for large datasets in multidimensional environments, with average O(n) time complexity when the map key distributes evenly.

Histogram Sort

Histogram sort is a variant of bucket sort designed for discrete data, particularly integers within a known range, where it first constructs a histogram—a frequency count of each possible value—to determine the exact allocation of elements into buckets based on their counts. This pre-allocation step ensures precise sizing of output positions without overflow risks, making it particularly suitable for stable sorting without requiring linked lists or dynamic resizing. The process begins with computing a histogram array of size equal to the range of possible values (denoted as r), where each entry records the frequency of a specific value in the input array of n elements; this initial pass takes O(n) time. Next, cumulative sums are calculated on the histogram to determine the starting positions for each value in the output array, enabling a second pass that directly places elements into their final sorted positions based on these offsets, also in O(n) time. If the data is discrete and buckets correspond to individual values (one per possible key), no inner sorting of buckets is needed, as the stable placement preserves order; for coarser bucketing, a final pass may sort non-empty buckets if required. This three-pass structure—count, cumulate, and place—distinguishes it from standard bucket sort's uniform distribution. A key benefit of histogram sort is its time complexity of O(n + r) in all cases, which is optimal when r is small relative to n, making it ideal for sorting small integer ranges such as grades, pixel intensities, or indices in databases. This linear performance stems from avoiding comparisons and leveraging direct index addressing, outperforming comparison-based sorts like quicksort for such inputs. As detailed in standard algorithm analyses, it excels in scenarios with known bounded domains, providing constant factors that are minimal due to the simplicity of array operations. (referring to Volume 3: Sorting and Searching) Histogram sort is essentially a bucketed implementation of counting sort, where fixed buckets are assigned one per possible value, transforming the general distribution problem into exact positional placement via the histogram. Counting sort itself, the foundational form of this approach, was developed by Harold H. Seward in 1954 as an efficient method for sorting limited-range data in electronic computing applications. This relation highlights histogram sort's role as a refinement, extending counting sort's ideas to scenarios where buckets may aggregate multiple values while retaining the frequency-based efficiency. A primary limitation of histogram sort is its inefficiency for large ranges r \gg n, as the histogram array consumes O(r) space and time, potentially leading to impractical memory usage without techniques like range compression or sparse representations. This makes it unsuitable for unbounded or floating-point data unless the range is artificially bounded, contrasting with more flexible bucket sort variants.

Postman's Sort

Postman's sort is a variant of bucket sort designed for sorting records with hierarchical or multi-attribute keys, such as strings or formatted numbers, by distributing elements into buckets based on successive key components. It emulates the process a postman uses to sort mail: first grouping letters by the initial character or attribute, then subdividing those groups by the next character, and continuing recursively until each subgroup is fully ordered. This approach leverages the structured nature of the keys to efficiently allocate and fill buckets, making it particularly effective for data where keys follow predictable patterns, like alphabetic names or numeric identifiers in real-world applications such as postal or database sorting. The algorithm proceeds in passes over the input. In the initial pass, elements are distributed into buckets corresponding to the most significant key attribute (e.g., 26 buckets for A-Z in alphabetic keys). Each non-empty bucket is then recursively processed using the next key attribute, creating finer subdivisions until the subgroups contain elements with identical keys or are small enough to sort via insertion or another stable method. Finally, the sorted buckets are concatenated in order to produce the output sequence. An optional step can apply an inverse permutation if stability is required, though the core method preserves relative order within equal keys through stable bucket sorting. This hierarchical bucketing avoids the need for uniform distribution assumptions by tailoring bucket counts to the key's structure, handling skewed real-world data like clustered social security numbers or non-random names effectively. Developed by Robert Ramey and detailed in a 1992 article in C Users Journal, the algorithm was implemented as a practical tool for sorting large files of records, outperforming comparison-based sorts in benchmarks. For instance, on 100,000 records with fixed-length keys, it achieved speeds up to 12 times faster than quicksort, and 16 times for variable-length keys, due to its linear scaling with input size. The time complexity is O(n + k \cdot m), where n is the number of elements, k the number of buckets per level, and m the key length, approaching O(n \cdot m) in practice for optimized configurations; this yields near-linear performance with high probability for structured data, as each element is touched a constant number of times proportional to key depth. Despite its efficiency, Postman's sort introduces variability from the recursive depth and bucket sizing, which depend on key format specifications provided as input parameters (e.g., via command-line options for digit ranges). It is not fully deterministic without fixed key assumptions and requires upfront knowledge of the data's key structure to avoid inefficient bucket allocations, limiting its generality compared to adaptive sorts. In scenarios with highly irregular or unknown key distributions, performance can degrade if buckets become unbalanced, though adaptations like dynamic bucket resizing mitigate this in practical implementations.

Shuffle Sort

Shuffle sort is a distribution-based sorting algorithm that serves as a variant of bucket sort, designed to handle inputs with unknown or varying distributions. The algorithm operates by first extracting a sample of the input data—specifically, the first n/8 elements—and sorting them recursively to estimate the overall distribution. This sorted sample is then used to define the boundaries for n/8 buckets, ensuring the buckets are adaptive to the data's characteristics. The remaining 7n/8 elements are subsequently distributed into these buckets based on their values relative to the sample-derived boundaries. Each bucket is then sorted recursively using the same method, and the results are concatenated in order to form the final sorted array. The key innovation in shuffle sort lies in its sample-based estimation technique, which allows for dynamic bucket creation without requiring predefined range knowledge, thereby improving robustness over fixed-bucket approaches in bucket sort. This method constructs a wide tree-like structure akin to a B-tree with a branching factor of m = n/8, promoting balanced partitioning and efficient recursive processing. By leveraging the initial sample for distribution estimation, shuffle sort avoids the need for extensive preprocessing while maintaining the core principles of distribution sorting. This variant finds applications in environments where memory constraints are moderate and the input distribution cannot be assumed uniform, such as in general-purpose sorting libraries that integrate multiple distribution techniques. It assumes that the sample reasonably represents the full dataset, leading to expected linear time performance under uniform conditions, though it remains vulnerable to poor sampling that could unbalance buckets. Trade-offs include elevated constant factors from the recursive sampling and sorting steps, which can make it less efficient than non-recursive variants for small inputs, alongside a worst-case time complexity of O(n²) if the distribution estimation fails to produce even buckets. Unlike some space-optimized variants, shuffle sort typically requires auxiliary space proportional to the number of buckets for distribution, though optimizations can reference the overall space analysis of bucket sorts. It builds upon foundational ideas in bucket sort variants like Postman's sort by emphasizing adaptive partitioning, but prioritizes distribution estimation over hierarchical key processing to enhance space utilization in recursive calls.

Comparisons

With Comparison-Based Sorts

Bucket sort, as a non-comparison-based algorithm, offers an average time complexity of O(n + k) for uniformly distributed inputs, where n is the number of elements and k is the number of buckets, outperforming quicksort's average O(n \log n) in such scenarios. However, bucket sort is non-adaptive to the data distribution and can degrade to O(n^2) in the worst case if most elements fall into a single bucket, whereas quicksort maintains O(n \log n) average performance across general inputs and only reaches O(n^2) in pathological cases mitigated by randomized pivot selection. In comparison to mergesort, bucket sort provides potential average linear time under favorable distributions, while mergesort guarantees O(n \log n) in all cases through its divide-and-conquer approach. Bucket sort typically requires O(n + k) space for the buckets and temporary storage, which may be comparable to or slightly higher than mergesort's O(n) auxiliary space depending on k, but both algorithms support in-place variations with trade-offs in stability or efficiency. Regarding stability, bucket sort preserves the relative order of equal elements if a stable sorting algorithm, such as insertion sort or mergesort, is used within each bucket; quicksort is generally unstable, potentially rearranging equal elements, while mergesort is inherently stable in its standard implementation. Bucket sort is most advantageous for inputs with a known bounded range and uniform distribution, enabling its linear average-case performance without relying on comparisons; in contrast, quicksort and mergesort are preferred for arbitrary or non-uniform data where distribution assumptions cannot be made, ensuring consistent O(n \log n) behavior.
AlgorithmAverage Time ComplexityWorst-Case Time ComplexitySpace Complexity
Bucket SortO(n + k)O(n^2)O(n + k)
QuicksortO(n \log n)O(n^2)O(\log n)
MergesortO(n \log n)O(n \log n)O(n)

With Distribution-Based Sorts

Bucket sort shares foundational principles with other distribution-based sorting algorithms, such as counting sort and radix sort, but differs in its applicability and mechanics. Unlike counting sort, which is optimized for sorting a small set of integers within a known range, bucket sort generalizes the approach to handle real numbers by distributing elements into buckets based on their fractional values and then sorting each bucket individually. Counting sort achieves a time complexity of O(n + r), where n is the number of elements and r is the input range, without needing an inner sorting step, as it relies solely on counting occurrences to reconstruct the sorted array. In relation to radix sort, bucket sort operates similarly to a least-significant-digit (LSD) radix sort variant tailored for floating-point numbers, partitioning elements into buckets rather than processing digits iteratively. Radix sort requires O(d(n + b)) time, where d is the number of digits and b is the base, typically involving multiple passes over the data for multi-digit keys, while bucket sort simplifies this to a single distribution pass followed by per-bucket sorting. These algorithms, including bucket sort, exhibit key shared traits as non-comparison sorts: they avoid element pairwise comparisons, achieve linear average-case time complexity under uniform input distributions, and have performance that scales with the input range or number of buckets rather than solely with n. Bucket sort particularly excels in scenarios involving continuous values, such as uniformly distributed floating-point numbers in [0, 1), where the absence of discrete digit structures makes radix sort less straightforward. Historically, bucket sort emerged as a standard introductory example of distribution-based sorting in algorithms literature during the 1970s, taught alongside counting and radix sorts without attribution to a single inventor, reflecting the era's focus on linear-time methods for specific data distributions.