美文网首页
Swift 5 排序算法 O(n log n)

Swift 5 排序算法 O(n log n)

作者: Sunooo | 来源:发表于2023-03-20 23:16 被阅读0次

时间复杂度O(n log n)的排序算法

以下排序算法的时间复杂度都是O(n log n)

归并排序

分而治之的思想,将数组不断向下二分,直到将相邻2个元素比较排序,再相邻4个元素比较排序,直到所有元素比较完毕。

public func mergeSort<Element: Comparable>(_ array: [Element]) -> [Element] {
    guard array.count > 1 else { return array }
    let middle = array.count / 2
    let left = mergeSort(Array(array[..<middle]))
    let right = mergeSort(Array(array[middle...]))
    
    return merge(left, right)
}

private func merge<Element: Comparable>(_ left: [Element], _ right: [Element]) -> [Element] {
    var leftIndex = 0
    var rightIndex = 0

    var result: [Element] = []
    while leftIndex < left.count, rightIndex < right.count {
        let leftElement = left[leftIndex]
        let rightElement = right[rightIndex]
        if leftElement < rightElement {
            result.append(leftElement)
            leftIndex += 1
        } else if leftElement > rightElement {
            result.append(rightElement)
            rightIndex += 1
        } else {
            result.append(leftElement)
            leftIndex += 1
            result.append(rightElement)
            rightIndex += 1
        }
    }

    if leftIndex < left.count {
        result.append(contentsOf: left[leftIndex...])
    }

    if rightIndex < right.count {
        result.append(contentsOf: right[rightIndex...])
    }
    return result
}

基数排序

按照整数的长度进行排序

public extension Array where Element == Int {
    mutating func radixSort() {
        let base = 10
        var done = false
        var digits = 1
        while !done {
            done = true
            var buckets: [[Int]] = .init(repeating: [], count: base)

            forEach { number in
                let remainingPart = number / digits
                let digit = remainingPart % base
                buckets[digit].append(number)
                if remainingPart > 0 {
                    done = false
                }
            }
            digits *= base
            self = buckets.flatMap { $0 }
        }
    }
}

堆排序

构造一个堆结构,利用堆的性质,进行排序

struct Heap<Element: Equatable> {
    var elements: [Element] = []
    let sort: (Element, Element) -> Bool
    init(sort: @escaping (Element, Element) -> Bool, elements: [Element]) {
        self.sort = sort
        self.elements = elements
        
        if !elements.isEmpty {
            for i in stride(from: elements.count / 2 - 1, through: 0, by: -1) {
                siftDown(from: i)
            }
        }
    }
    
    var isEmpty: Bool {
        elements.isEmpty
    }
    
    var count: Int {
        elements.count
    }
    
    func peek() -> Element? {
        elements.first
    }
    
    func leftChildIndex(ofParentAt index: Int) -> Int {
        (2 * index) + 1
    }
    
    func rightChildIndex(ofParentAt index: Int) -> Int {
        (2 * index) + 2
    }
    
    func parentIndex(ofChildAt index: Int) -> Int {
        (index - 1) / 2
    }
}

extension Heap {
    mutating func remove() -> Element? {
        guard !isEmpty else { return nil }
        elements.swapAt(0, count - 1)
        defer {
            siftDown(from: 0)
        }
        return elements.removeLast()
    }
    
    mutating func siftDown(from index: Int) {
        var parent = index
        while true {
            let left = leftChildIndex(ofParentAt: parent)
            let right = rightChildIndex(ofParentAt: parent)
            var candidate = parent
            if left < count, sort(elements[left], elements[candidate]) {
                candidate = left
            }
            if right < count, sort(elements[right], elements[candidate]) {
                candidate = right
            }
            if candidate == parent {
                return
            }
            elements.swapAt(parent, candidate)
            parent = candidate
        }
    }
    mutating func siftDown(from index: Int, upTo size: Int) {
        var parent = index
        while true {
            let left = leftChildIndex(ofParentAt: parent)
            let right = rightChildIndex(ofParentAt: parent)
            var candidate = parent
            if left < size, sort(elements[left], elements[candidate]) {
                candidate = left
            }
            if right < size, sort(elements[left], elements[candidate]) {
                candidate = right
            }
            if candidate == parent {
                return
            }
            elements.swapAt(parent, candidate)
            parent = candidate
            
        }
    }
    
    mutating func insert(_ element: Element) {
        elements.append(element)
        siftUp(from: elements.count - 1)
    }
    
    mutating func siftUp(from index: Int) {
        var child = index
        var parent = parentIndex(ofChildAt: child)
        while child > 0, sort(elements[child], elements[parent]) {
            elements.swapAt(child, parent)
            parent = parentIndex(ofChildAt: child)
        }
    }
    
    mutating func remove(at index: Int) -> Element? {
        guard index < elements.count else {
            return nil
        }
        if index == elements.count - 1 {
            return elements.removeLast()
        } else {
            elements.swapAt(index, elements.count - 1)
            defer {
                siftDown(from: index)
                siftDown(from: index)
            }
            return elements.removeLast()
        }
    }
    
    func index(of element: Element, startingAt i: Int) -> Int? {
        if i >= count {
            return nil
        }
        if sort(element, elements[i]) {
            return nil
        }
        if element == elements[i] {
            return i
        }
        if let j = index(of: element, startingAt: leftChildIndex(ofParentAt: i)) {
            return j
        }
        
        if let j = index(of: element, startingAt: rightChildIndex(ofParentAt: i)) {
            return j
        }
        return nil
    }
}

// MARK: - Heap Sort
extension Heap {
    func sorted() -> [Element] {
        var heap = Heap(sort: sort, elements: elements)
        for index in heap.elements.indices.reversed() {
            heap.elements.swapAt(0, index)
            heap.siftDown(from: 0, upTo: index)
        }
        return heap.elements
    }
}

快速排序

分而治之,在一个点, 把一串数组拆分为两串,然后递归进行下去。

public func quicksortNaive<Element: Comparable>(_ a: [Element]) -> [Element] {
    guard a.count > 1 else { return a }
    let pivot = a[a.count / 2]
    let less = a.filter { $0 < pivot }
    let equal = a.filter { $0 == pivot }
    let greater = a.filter { $0 > pivot }
    return quicksortNaive(less) + equal + quicksortNaive(greater)
}

github仓库地址 https://github.com/SunZhiC/DataStructuresInSwift

References

Data Structures & Algorithms in Swift by Matthijs Hollemans.
https://github.com/apple/swift-algorithms
https://github.com/raywenderlich/swift-algorithm-club

相关文章

  • 快速排序与归并排序Java实现版

    快速排序 快速排序(Quicksort) 是一种排序算法,平均时间复杂度为:O(n log n),最坏需要 O(n...

  • 常用算法复杂度

    o(1)

  • 算法与数据结构系列 ( 一 ) - 算法的级别区分理解

    算法的级别 O(1)、O(n)、O(n^2)、O(log n)、O(n log n)这些都是算法时间空间复杂度的表...

  • 算法比较

    排序算法平均时间复杂度冒泡排序O(n²)选择排序O(n²)插入排序O(n²)希尔排序O(n1.5)快速排序O(N*...

  • python 八大算法

    排序算法总结 排序算法 平均时间复杂度 冒泡排序O(n2) 选择排序O(n2) 插入排序O(n2) 希尔排序O(n...

  • 斐波那契

    1、O(n)的算法 2、O(2^n)的算法 3、O(1)的算法 4、O(log n)的算法 参考: https:/...

  • 快速排序

    分类:排序算法 数据结构:不定 最坏时间复杂度:O(n^2) 最优时间复杂度:O(n log n) 平均时间复杂度...

  • 排序算法小总结

    排序算法时间复杂度冒泡排序O(n2)选择排序O(n2)插入排序O(n2)希尔排序O(n1.5)快速排序O(N*lo...

  • 常用排序算法总结4一一归并排序

    定义 归并排序(英语:Merge sort),是创建在归并操作上的一种有效的排序算法,效率为O(n log n)。...

  • 排序算法总结

    排序算法总结 分类编程技术 排序算法平均时间复杂度 冒泡排序O(n2) 选择排序O(n2) 插入排序O(n2) 希...

网友评论

      本文标题:Swift 5 排序算法 O(n log n)

      本文链接:https://www.haomeiwen.com/subject/ckmuqltx.html