Swift Program to Implement Bucket Sort

Swift Program to Implement Bucket Sort

Bucket Sort is a simple yet powerful sorting algorithm that organizes data by dividing it into smaller groups, called buckets, and then sorting each bucket individually. This method is particularly useful when you know the range of your input data or when your data is spread relatively uniformly. Instead of comparing each element with every other element, Bucket Sort takes advantage of grouping, which can make the sorting process much faster in the right situations.

Pluralsight Logo
Accelerate your tech career
with hands-on learning.
Whether you're a tech newbie or a total pro,
get the skills and confidence to land your next move.
Start 10-Day Free Trial

This algorithm is often used in applications where speed matters and the data is predictable, such as sorting floating-point numbers, grades, or scores. By learning Bucket Sort in Swift, beginners can get hands-on experience with both arrays and sorting strategies, and it also teaches a structured approach to breaking problems into smaller, more manageable parts. Swift’s clean syntax makes it easy to write and understand Bucket Sort, even for newcomers.

Program 1: Basic Bucket Sort with Loops

This first program demonstrates a simple Bucket Sort for floating-point numbers between 0 and 1. It divides the numbers into buckets, sorts each bucket individually, and then merges them back together.

import Foundation

func bucketSort(_ array: [Double]) -> [Double] {

    let n = array.count
    guard n > 0 else { return array }

    var buckets: [[Double]] = Array(repeating: [], count: n)

    for number in array {
        let index = Int(number * Double(n))
        buckets[index].append(number)
    }

    for i in 0..<n {
        buckets[i].sort()
    }

    return buckets.flatMap { $0 }

}

let data: [Double] = [0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21, 0.12, 0.23, 0.68]

let sortedData = bucketSort(data)

print("Sorted array:", sortedData)

This program works by first distributing the values into several buckets based on their range. Each bucket is then sorted individually, using Swift’s built-in sort for simplicity. Beginners can see clearly how the data moves from unsorted to sorted step by step, and the logic of grouping before sorting makes the algorithm easy to follow.

Program 2: Bucket Sort with Custom Sorting Function

Here, we enhance the algorithm by using a custom sorting function for each bucket. This shows how Swift’s flexible functions can be applied in real-world sorting tasks.

import Foundation

func bucketSortDescending(_ array: [Double]) -> [Double] {

    let n = array.count
    guard n > 0 else { return array }

    // Initialize buckets
    var buckets: [[Double]] = Array(repeating: [], count: n)

    // Distribute elements into buckets
    for number in array {

        let index = min(Int(number * Double(n)), n - 1) // Ensure index is in range
        buckets[index].append(number)

    }

    // Sort each bucket in descending order
    for i in 0..<n {
        buckets[i].sort(by: >)
    }

    // Flatten buckets in reverse order to get true global descending order
    return buckets.reversed().flatMap { $0 }

}

let data2: [Double] = [0.25, 0.36, 0.58, 0.41, 0.29, 0.22]

let sortedData2 = bucketSortDescending(data2)

print("Globally descending sorted array:", sortedData2)

This version allows you to control how each bucket is sorted. It helps beginners understand that Bucket Sort is not restricted to a specific sorting method within each bucket. The flexibility makes it easier to adapt the algorithm for different needs.

Program 3: Bucket Sort Using Recursion for Each Bucket

This program demonstrates sorting each bucket recursively instead of using Swift’s built-in sort. It gives learners a chance to see recursion applied in practice.

import Foundation

func recursiveSort(_ array: [Double]) -> [Double] {

    if array.count <= 1 { return array }

    let pivot = array[array.count / 2]
    let smaller = array.filter { $0 < pivot }
    let equal = array.filter { $0 == pivot }
    let larger = array.filter { $0 > pivot }

    return recursiveSort(smaller) + equal + recursiveSort(larger)

}

func bucketSortRecursive(_ array: [Double]) -> [Double] {

    let n = array.count
    guard n > 0 else { return array }

    var buckets: [[Double]] = Array(repeating: [], count: n)

    for number in array {

        let index = Int(number * Double(n))
        buckets[index].append(number)

    }

    for i in 0..<n {
        buckets[i] = recursiveSort(buckets[i])
    }

    return buckets.flatMap { $0 }

}

let data3: [Double] = [0.54, 0.12, 0.33, 0.71, 0.41, 0.88]

let sortedData3 = bucketSortRecursive(data3)

print("Recursively sorted array:", sortedData3)

Using recursion inside each bucket demonstrates how sorting can be applied multiple times in smaller subsets. Beginners will appreciate seeing a familiar recursive pattern used in a new context, making the concept of divide-and-conquer more tangible.

Program 4: Bucket Sort for Integers

This example adapts Bucket Sort to work with integer values by normalizing them into a specific range. It is useful when your data is not limited to 0–1 floating-point numbers.

import Foundation

func bucketSortIntegers(_ array: [Int]) -> [Int] {

    guard let maxValue = array.max(), array.count > 0 else { return array }

    let n = array.count
    var buckets: [[Int]] = Array(repeating: [], count: n)

    for number in array {

        let index = Int(Double(number) / Double(maxValue) * Double(n - 1))
        buckets[index].append(number)

    }

    for i in 0..<n {
        buckets[i].sort()
    }

    return buckets.flatMap { $0 }

}

let data4: [Int] = [42, 32, 33, 52, 37, 47, 51]
let sortedData4 = bucketSortIntegers(data4)

print("Sorted integers:", sortedData4)

By scaling integers into a range of buckets, this approach shows that Bucket Sort is flexible. Beginners learn how normalization can adapt the algorithm to work with different types of data.

Program 5: Generic Bucket Sort Using Comparable Types

This version uses Swift generics to create a flexible and reusable Bucket Sort that works with any comparable type, including integers, floating-point numbers, or even custom types with a defined order. Instead of relying on a key function, it automatically normalizes all values to a range of [0, 1] and distributes them into buckets. This ensures that numbers of any magnitude, including negatives, can be mapped correctly into buckets and sorted efficiently.

import Foundation

func genericBucketSortNormalized<T: Comparable & BinaryFloatingPoint>(_ array: [T], bucketCount: Int) -> [T] {

    guard !array.isEmpty else { return array }

    guard let minValue = array.min(), let maxValue = array.max(), minValue != maxValue else { return array }

    var buckets: [[T]] = Array(repeating: [], count: bucketCount)

    for item in array {

        let normalized = (item - minValue) / (maxValue - minValue)
        let index = min(Int(normalized * T(bucketCount - 1)), bucketCount - 1)

        buckets[index].append(item)

    }

    for i in 0..<bucketCount { buckets[i].sort() }

    return buckets.flatMap { $0 }

}

// Example 1: Integers as Doubles
let intData: [Double] = [15, 42, 37, 8, 23, 4]

let sortedInts = genericBucketSortNormalized(intData, bucketCount: 6)
print("Sorted integers:", sortedInts)


// Example 2: Floating-point numbers
let floatData: [Double] = [0.25, 0.36, 0.58, 0.41, 0.29, 0.22]
let sortedFloats = genericBucketSortNormalized(floatData, bucketCount: 6)

print("Sorted floats:", sortedFloats)

By using generics, this approach demonstrates how the same algorithm can be reused across multiple numeric types, keeping your code concise and efficient. Beginners can see the power of reusable Swift functions without needing separate implementations for integers or floating-point numbers.

Program 6: Generic Bucket Sort Handling Negatives – Integers and Floats

This enhanced version builds on Program 5 to make handling negatives more explicit. It separates negative and positive numbers, sorts each group individually using the same normalization technique, then recombines them. This ensures that arrays containing both positive and negative numbers are correctly sorted while keeping the logic clear and beginner-friendly.

import Foundation

func genericBucketSortWithNormalization<T: Comparable & BinaryFloatingPoint>(
    _ array: [T],
    bucketCount: Int
) -> [T] {

    guard !array.isEmpty else { return array }

    let positives = array.filter { $0 >= 0 }
    let negatives = array.filter { $0 < 0 }.map { -$0 }

    func sortPositive(_ arr: [T]) -> [T] {

        guard let minValue = arr.min(), let maxValue = arr.max(), minValue != maxValue else { return arr }
        var buckets: [[T]] = Array(repeating: [], count: bucketCount)

        for item in arr {

            let normalized = (item - minValue) / (maxValue - minValue)
            let index = min(Int(normalized * T(bucketCount - 1)), bucketCount - 1)

            buckets[index].append(item)

        }

        for i in 0..<bucketCount { buckets[i].sort() }

        return buckets.flatMap { $0 }

    }

    let sortedPos = sortPositive(positives)
    let sortedNeg = sortPositive(negatives).reversed().map { -$0 }

    return sortedNeg + sortedPos

}

// Example 1: Integers including negatives
let intDataNeg: [Double] = [42, -96, 33, -7, 51]
let sortedIntsNeg = genericBucketSortWithNormalization(intDataNeg, bucketCount: 5)

print("Sorted integers with negatives:", sortedIntsNeg)


// Example 2: Floating-point numbers including negatives
let floatDataNeg: [Double] = [0.78, -0.17, 0.39, -0.26, 0.72, -0.94, 0.21]
let sortedFloatsNeg = genericBucketSortWithNormalization(floatDataNeg, bucketCount: 7)

print("Sorted floats with negatives:", sortedFloatsNeg)

In this version, negatives are temporarily converted to positives, normalized, and sorted using buckets. After sorting, they are reversed and restored to their original sign before combining with positives. This ensures the final array is correctly ordered, while the logic remains clear, reusable, and easy to understand.

Both programs 5 and 6 show how normalization plus generics allows Swift functions to handle any numeric dataset—positive or negative, integer or floating-point—without requiring a custom key function. Program 5 is ideal for straightforward datasets, while Program 6 makes negative handling explicit for clarity and teaching purposes.

Frequently Asked Questions (FAQ)

This FAQ section answers common questions beginners often have about Bucket Sort.

Q1: When should I use Bucket Sort?
Bucket Sort works best when data is uniformly distributed or you know the range in advance. It’s efficient for floating-point numbers or integers that fit within a limited range.

Q2: Can Bucket Sort handle negative numbers?
Yes, you can adjust the algorithm to normalize negatives into positive buckets before sorting.

Q3: How is Bucket Sort different from Quick Sort or Merge Sort?
Bucket Sort groups data into buckets before sorting, rather than comparing elements one by one. Quick Sort and Merge Sort rely on comparisons between all elements.

Q4: Is Bucket Sort stable?
It can be stable if the sorting method used within each bucket preserves the order of equal elements.

Q5: Can Bucket Sort be used for strings?
Yes, by using character codes or other numeric representations, Bucket Sort can sort strings or other comparable types.

Conclusion

Bucket Sort is a friendly, beginner-accessible algorithm that teaches important programming concepts like grouping, normalization, and sorting subsets. By trying the different Swift implementations above, you can see how loops, recursion, generics, and custom sorting functions can all be applied. Practicing with different data types will build confidence and give you a solid understanding of both Bucket Sort and general sorting strategies in Swift.

Scroll to Top