Skip to content

Sorting Algorithms Compared

Ever wondered how sorting algorithms looked in Swift? I did too — so I implemented some. Below you can find the following:

  • Bubble Sort
  • Selection Sort
  • Insertion Sort
  • Merge Sort
  • Quicksort

As a preface: some of the algorithms use a self-implemented swap function — it is as follows:

extension Array {
    mutating func swap(i: Int, _ j: Int) {
        (self[i], self[j]) = (self[j], self[i])
    }
}

Bubble Sort

func bubbleSort(var unsorted: Array<Int>) -> Array<Int> {
    for i in 0..<unsorted.count - 1 {
        for j in 0..<unsorted.count - i - 1 {
            if unsorted[j] > unsorted[j + 1] {
                unsorted.swap(j, j + 1)
            }
        }
    }
    
    return unsorted
}

Selection Sort

func selectionSort(var unsorted: Array<Int>) -> Array<Int> {
    for i in 0..<unsorted.count - 1 {
        var minimumIndex = i
        for j in i + 1 ..< unsorted.count {
            if unsorted[j] < unsorted[minimumIndex] {
                minimumIndex = j
            }
            unsorted.swap(minimumIndex, i)
        }
    }
    
    return unsorted
}

Insertion Sort

func insertionSort(var unsorted: Array<Int>) -> Array<Int> {
    for j in 1...unsorted.count - 1 {
        let key = unsorted[j];
        var i = j - 1
        
        while i >= 0 && unsorted[i] > key {
            unsorted[i + 1] = unsorted[i]
            i--
        }
        
        unsorted[i + 1] = key
    }
    
    return unsorted
}

Merge Sort

func merge(leftArray left: Array<Int>, rightArray right: Array<Int>) -> Array<Int> {
    var result = [Int]()
    var leftIndex = 0, rightIndex = 0
    
    // Calculated variable to determine if the indexes have reached end of their respective arrays
    var indexesHaveReachedEndOfArrays: Bool { return leftIndex < left.count && rightIndex < right.count }
    
    while indexesHaveReachedEndOfArrays {
        if left[leftIndex] < right[rightIndex] {
            result.append(left[leftIndex])
            leftIndex++
        }
        else if left[leftIndex] > right[rightIndex] {
            result.append(right[rightIndex])
            rightIndex++
        }
        else {
            result.append(left[leftIndex])
            result.append(right[rightIndex])
            
            leftIndex++
            rightIndex++
        }
    }
    
    result += Array(left[leftIndex..<left.count])
    result += Array(right[rightIndex..<right.count])
    
    return result
}

func mergesort(unsorted: Array<Int>) -> Array<Int> {
    let size = unsorted.count
    if size < 2 { return unsorted }
    
    let split = Int(size / 2)
    
    let left = Array(unsorted[0 ..< split])
    let right = Array(unsorted[split ..< size])
    
    let sorted = merge(leftArray: mergesort(left), rightArray: mergesort(right))
    return sorted
}

Quick Sort

func quicksort(var unsorted: Array<Int>) -> Array<Int> {
    quicksort(&unsorted, firstIndex: 0, lastIndex: unsorted.count - 1)
    return unsorted
}

private func quicksort(inout unsorted: Array<Int>, firstIndex: Int, lastIndex: Int) -> Array<Int> {
    if firstIndex < lastIndex {
        let split = partition(&unsorted, firstIndex: firstIndex, lastIndex: lastIndex)
        
        quicksort(&unsorted, firstIndex: firstIndex, lastIndex: split - 1)
        quicksort(&unsorted, firstIndex: split + 1, lastIndex: lastIndex)
    }
    
    return unsorted
}

private func partition(inout unsorted: Array<Int>, firstIndex: Int, lastIndex: Int) -> Int {
    let pivot = unsorted[lastIndex]
    var wall = firstIndex
    
    for i in firstIndex ... lastIndex - 1 {
        if unsorted[i] <= pivot {
            unsorted.swap(wall, i)
            wall++
        }
    }
    
    unsorted.swap(wall, lastIndex)
    return wall
}