iOS 冒泡排序(Bubble Sort)

algo

冒泡排序是一種簡單的排序算法。它重復(fù)地走訪過要排序的數(shù)列,一次比較兩個元素,如果它們的順序錯誤就把它們交換過來。走訪數(shù)列的工作是重復(fù)地進(jìn)行直到?jīng)]有再需要交換,也就是說該數(shù)列已經(jīng)排序完成。這個算法的名字由來是因為越小的元素會經(jīng)由交換慢慢“浮”到數(shù)列的頂端。

算法過程描述
  1. 比較相鄰的元素。如果第一個比第二個大,就交換它們兩個;
  2. 對每一對相鄰元素作同樣的操作,從開始第一對到結(jié)尾的最后一對,這樣在最后的元素應(yīng)該會是最大的數(shù);
  3. 針對所有的元素重復(fù)以上的步驟,除了最后一個;
  4. 重復(fù)步驟1~3,直到?jīng)]有任何一對數(shù)字需要比較。
動圖演示
bubbleSort.gif
復(fù)雜度

假設(shè)序列有n個元素,n>1,根據(jù)算法步驟,第1輪需在n個元素中兩兩比較(n-1)次,第2輪需要在剩余的(n-1)個元素中兩兩比較(n-2)次,第(n-1)輪需在最后2個元素中僅比較1次。

函數(shù)表達(dá)式為:
f(n) = (n-1) + (n-2) +...+ 2 + 1
f(n) = n*(n-1)/2
f(n) = (n2 - n)/2

大O表示法,忽略常量、低階和常數(shù)系數(shù)。

時間復(fù)雜度為:O(n2)
空間復(fù)雜度為:并未開辟額外空間, 所以為O(1)
穩(wěn)定性: 穩(wěn)定

代碼實現(xiàn)(Swift)

假設(shè)要對以下數(shù)組進(jìn)行冒泡排序:

let numbers = [1, 4, 3, 2, 0, 5, 6, 7, 8, 9]

n個元素進(jìn)行冒泡排序,總共需要重復(fù)遍歷(n-1)輪,每一輪遍歷結(jié)束后,最后一個元素會是排序數(shù)列中最大的元素,下一輪遍歷可少遍歷一個數(shù),因此第i輪遍歷需要比較(n-1-i)次。

func simpleBubbleSort(numbers: [Int]) -> [Int] {
    
    var sortedNumbers = numbers
    
    for i in 0..<sortedNumbers.count - 1 {
        
        print("\n\(sortedNumbers) (\(i)th circle begin)")
        
        for j in 0..<(sortedNumbers.count - 1 - i){
            
            if sortedNumbers[j] > sortedNumbers[j+1] {
                sortedNumbers.swapAt(j, j+1)
                print("\(sortedNumbers) (swap at \(j) and \(j+1))")
            }
        }
    }
    return sortedNumbers
}

let sortedNumbers = simpleBubbleSort(numbers: numbers)
print("\n\(sortedNumbers) (sample bubble sort result)")

終端打印結(jié)果:

[1, 4, 3, 2, 0, 5, 6, 7, 8, 9] (0th circle begin)
[1, 3, 4, 2, 0, 5, 6, 7, 8, 9] (swap at 1 and 2)
[1, 3, 2, 4, 0, 5, 6, 7, 8, 9] (swap at 2 and 3)
[1, 3, 2, 0, 4, 5, 6, 7, 8, 9] (swap at 3 and 4)

[1, 3, 2, 0, 4, 5, 6, 7, 8, 9] (1th circle begin)
[1, 2, 3, 0, 4, 5, 6, 7, 8, 9] (swap at 1 and 2)
[1, 2, 0, 3, 4, 5, 6, 7, 8, 9] (swap at 2 and 3)

[1, 2, 0, 3, 4, 5, 6, 7, 8, 9] (2th circle begin)
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9] (swap at 1 and 2)

[1, 0, 2, 3, 4, 5, 6, 7, 8, 9] (3th circle begin)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (swap at 0 and 1)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (4th circle begin)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (5th circle begin)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (6th circle begin)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (7th circle begin)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (8th circle begin)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (sample bubble sort result)

可以看到,第3輪遍歷后已經(jīng)排序完成:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

通過第4輪遍歷發(fā)現(xiàn)不再進(jìn)行位置交換,可以確定已為有序數(shù)組,那么后面的遍歷和比較其實毫無意義了,因此可以增加一個變量來優(yōu)化冒泡排序。

代碼優(yōu)化

增加一個Bool變量swapped來記錄每次是否發(fā)生位置交換,如果沒有發(fā)生位置交換,說明已經(jīng)是有序數(shù)列了,可以提前結(jié)束排序。

func betterBubbleSort(numbers: [Int]) -> [Int] {
    
    var sortedNumbers = numbers
    
    for i in 0..<sortedNumbers.count - 1 {
    
        var swapped = false
        
        print("\n\(sortedNumbers) (\(i)th circle begin, 1..<\(sortedNumbers.count-i))");
        
        for j in 0..<sortedNumbers.count - 1 - i {
            
            if sortedNumbers[j] > sortedNumbers[j+1] {
                sortedNumbers.swapAt(j, j+1)
                swapped = true
                print("\(sortedNumbers) (swap at \(j) and \(j+1))")
            }
        }
        
        if !swapped {
            print("排序已提前完成")
            break
        }
    }
    return sortedNumbers
}

let sortedNumbers = betterBubbleSort(numbers: numbers)
print("\n\(sortedNumbers) (better bubble sort result)")

終端打印結(jié)果如下:

[1, 4, 3, 2, 0, 5, 6, 7, 8, 9] (0th circle begin, 1..<10)
[1, 3, 4, 2, 0, 5, 6, 7, 8, 9] (swap at 1 and 2)
[1, 3, 2, 4, 0, 5, 6, 7, 8, 9] (swap at 2 and 3)
[1, 3, 2, 0, 4, 5, 6, 7, 8, 9] (swap at 3 and 4)

[1, 3, 2, 0, 4, 5, 6, 7, 8, 9] (1th circle begin, 1..<9)
[1, 2, 3, 0, 4, 5, 6, 7, 8, 9] (swap at 1 and 2)
[1, 2, 0, 3, 4, 5, 6, 7, 8, 9] (swap at 2 and 3)

[1, 2, 0, 3, 4, 5, 6, 7, 8, 9] (2th circle begin, 1..<8)
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9] (swap at 1 and 2)

[1, 0, 2, 3, 4, 5, 6, 7, 8, 9] (3th circle begin, 1..<7)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (swap at 0 and 1)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (4th circle begin, 1..<6)
排序已提前完成

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (better bubble sort result)

算法優(yōu)化后,雖然數(shù)組為有序,可提前結(jié)束遍歷;

但是仍可以發(fā)現(xiàn),0th輪遍歷最后一次交換發(fā)生在3, 4位置,即index 4開始后面的為有序數(shù)列。1th輪遍歷時,僅需遍歷1..<4,但可以該算法依然遍歷1..<9。

因此可以繼續(xù)優(yōu)化。

代碼再優(yōu)化

增加一個變量lastSwappedIndex來記錄最后一次交換的位置,下一輪遍歷時,只需遍歷1..<lastSwappedIndex即可。

func bestBubbleSort(numbers: [Int]) -> [Int] {
    
    var sortedNumbers = numbers
    
    var lastSwappedIndex = sortedNumbers.count
    
    for i in 0..<sortedNumbers.count - 1 {
        
        print("\n\(sortedNumbers) (\(i)th circle begin, 1..<\(lastSwappedIndex))");
        
        var swapped = false
        
        for j in 0..<lastSwappedIndex - 1 {
            
            if sortedNumbers[j] > sortedNumbers[j+1] {
                sortedNumbers.swapAt(j, j+1)
                swapped = true
                lastSwappedIndex = j+1
                print("\(sortedNumbers) (swap at \(j) and \(j+1))")
            }
        }
        
        if !swapped || lastSwappedIndex == 1 {
            print("排序已提前完成")
            break
        }
    }
    return sortedNumbers
}

let sortedNumbers = bestBubbleSort(numbers: numbers)
print("\n\(sortedNumbers) (best bubble sort result)")

終端打印結(jié)果如下:

[1, 4, 3, 2, 0, 5, 6, 7, 8, 9] (0th circle begin, 1..<10)
[1, 3, 4, 2, 0, 5, 6, 7, 8, 9] (swap at 1 and 2)
[1, 3, 2, 4, 0, 5, 6, 7, 8, 9] (swap at 2 and 3)
[1, 3, 2, 0, 4, 5, 6, 7, 8, 9] (swap at 3 and 4)

[1, 3, 2, 0, 4, 5, 6, 7, 8, 9] (1th circle begin, 1..<4)
[1, 2, 3, 0, 4, 5, 6, 7, 8, 9] (swap at 1 and 2)
[1, 2, 0, 3, 4, 5, 6, 7, 8, 9] (swap at 2 and 3)

[1, 2, 0, 3, 4, 5, 6, 7, 8, 9] (2th circle begin, 1..<3)
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9] (swap at 1 and 2)

[1, 0, 2, 3, 4, 5, 6, 7, 8, 9] (3th circle begin, 1..<2)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (swap at 0 and 1)
排序已提前完成

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (best bubble sort result)

可以看到,0th遍歷0..<10,第1th遍歷1..<4,后面有序的不再遍歷。

回目錄:常用的排序算法

結(jié)語

路漫漫其修遠(yuǎn)兮,吾將上下而求索~

作者簡書

作者掘金

作者GitHub

.End

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容