算法基礎--桶排序(計數排序,基數排序)

本文只是自己的筆記,並不具備過多的指導意義。

代碼的初衷是便於理解,網上大神優化過的代碼很多,也不建議在項目中copy本文代碼。


目錄

  • 桶排序
  • 記數排序
  • 基數排序
  • 桶排序

桶排序

桶排序並不是一個具體的排序,而是一個邏輯概念。

之所以叫桶,是因爲他會根據數據狀況設計出一個容器,裏面每個index將相當於一個桶。
在遍歷數據的時候將根據劃分將數據一次放入每個桶中,遍歷結束後將桶依次倒出。
在每個桶內部,數據會被處理成有序結構。
具體操作可以參考記數排序。

  • 桶排序的特點
  1. 非基於比較的排序,與被排序的樣本的實際數據狀況很有關係。
    並不能作爲一個通解被應用在普遍場景下,所以實際中並不經常使用。
  2. 時間複雜度O(N),額外空間複雜度O(N)
  3. 穩定的排序

記數排序

桶排序的具體實現,根據數據狀況的最大值開闢一個容器空間

核心在於將數據值轉化爲鍵存儲在額外開闢的容器空間中。
數據遍歷完成,將容器空間的數據填充給原數組。

/// 計數排序
///
/// - Parameters:
///   - arr: 目標數組
///   - max: 最大值
func countingSort(arr : inout [Int] ,max:Int)  {
    var containerArr = [Int](repeating: 0, count: max+1)  //生成長度爲最大值的容器數組
    var p = 0
    while p<arr.count {
        containerArr[arr[p]]+=1 //容器數組指定位置計數+1
        p+=1
    }
    p = 0
    var containerP = 0 //容器數組遍歷指針
    while containerP<max { //遍歷容器數組
        while containerArr[containerP]>0 { //如果容器數組指定位置大於0
            arr[p] = containerP //依次將容器數組的index填充回目標數組
            p+=1
            containerArr[containerP]-=1
        }
        containerP+=1
    }
}
算法的時間複雜度O(N),空間複雜度O(N),並且穩定

基數排序

也是桶排序的一種實現,相比記數排序堆桶的利用更加精緻。

具體實現上,從個位數開始,逐位進行排序。由於每次partition都是穩定的,從而保證整體有序。
通俗點來講,百位相同的數,按照十位排序,十位相同的數按照個位排序。

/// 基數排序
///
/// - Parameters:
///   - arr: 目標數組
///   - maxDigit: 最大位數
func radixSort(arr: inout [Int] ,maxDigit: Int) {
    var mod=10 //取餘
    var containerArr = [[Int]](repeating: [Int](repeating: 0, count: 0), count: 9) //創建一個長度爲9的二位容器數組
    
    while mod<=kt_pow(a: 10, b: maxDigit) {  //取餘位數 小於等於 最大位數 100/10 <=10^2
        var p = 0
        while p < arr.count { //在容器數組中,將原數組以某位的值進行排列
            //獲取某位的值
            let bucket = arr[p]%mod/(mod/10)  // 120%100=@20  ==> @20/(100/10) = 2
            containerArr[bucket].append(arr[p])  //加入有序數組的指定位置
            p+=1
        }
        
        p = 0
        while p < arr.count {  //將容器數組中的順序,回倒給原數組
            for index in 0..<containerArr.count {
                while containerArr[index].count>0 { //將容器數組指定位置的元素依次出隊
                    arr[p] = containerArr[index][0] //首位出隊
                    containerArr[index].remove(at: 0) //移除首位
                    p+=1
                }
            }
        }
        mod*=10 //對下一位進行排序
    }
}

/// 乘方運算
///
/// - Returns: a^b
func kt_pow(a:Int ,b:Int) -> Int {
    var a=a
    let c=a
    if b == 0 {
        return 1
    }
    
    var i = 1
    while i<b {
        a=a*c
        i+=1
    }

    return a
}
算法的時間複雜度O(N),空間複雜度O(N),並且穩定

桶排序

網上有寫了桶排序的,就是通過有限個數的桶,將數據源按區間放入,然後將某個桶內部排序。最後倒出。

感覺在桶內部排序的時候已經需要比較的排序方式了,違背了初衷吧。
有興趣自己可以看一下
十大經典排序算法(動圖演示)


參考資料

左神牛課網算法課
十大經典排序算法(動圖演示)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章