1、概述

冒泡排序是一种简单的算法,是指重复遍历需要排序的元素列,一次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母a~z等)错误就把他们交换过来,遍历的目的是重复的进行指导没有相邻元素需要交换 即该元素列已经排序完成。

2、算法原理

swift算法之排序:(一)冒泡排序_待排序

1)比较相邻的元素,如果第一个比第二个大,就交换他们两个

2)对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,在这一点,最后的元素会是最大的数

3)针对所有的元素重复以上的步骤,除了最后一个

4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

3、举例

需要对 1 4 6 2 8 这5个数按照从大到小的顺序进行排序

swift算法之排序:(一)冒泡排序_swift_02

1)首先,对第一位和第二位进行比较,明显 1<4,所以交换 1 和 4 的位置

swift算法之排序:(一)冒泡排序_冒泡_03

2)继续比较第二位和第三位,发现 1<6,所以交换 1 和 6 的位置

swift算法之排序:(一)冒泡排序_数组_04

3)继续比较第三位和第四位,1<2 ,交换 1 和 2 的位置

swift算法之排序:(一)冒泡排序_待排序_05

4)最后比较 第四位和第五位 ,1<8 ,交换 1 和 8 的位置

swift算法之排序:(一)冒泡排序_数组_06

经过上面一轮的比较,我们发现,1是最小的,且放在了最后。

下面是1上浮的过程,为什么说是上浮?是由于数字是存储在数组中的,在swift中,数组是先进后出的,栈一般在swift的实现都是通过数组。并且1的上浮过程像水泡从水底上浮到水面,所以 算法 叫 冒泡排序

swift算法之排序:(一)冒泡排序_待排序_07

剩余的元素依次按照上述操作继续比较,把最小的2放在倒数第二位,以此类推,最大的8位于首位

4、算法实现

1)一般实现

按照冒泡的原理,一般实现为

func bubbleSort(_ array : [Int]){
        var list = array
        //记录循环次数
        var count = 0
        for i in 0..<list.count {
            count = i
            for j in i+1..<list.count{
                if list[i] > list [j] {
                      //交换方式1
//                    let tmp = list[j]
//                    list[j] = list[i]
//                    list[i] = tmp
                    //交换方式2
                    list.swapAt(i, j)
                    //交换方式4
//                    (list[i], list[j]) = (list[j], list[i])
                    //交换方式5
//                    swap(&list[i], &list[j])

                }
            }
        }
        print(list)
        print("count: ",count)
    }

注:数据的交换过程在swift中有3种
1)定义变量交换
        let tmp = list[j]
        list[j] = list[i]
        list[i] = tmp
2)数组自带的交换方法
        list.swapAt(i, j)
3)使用元祖的交换方法
        (list[i], list[j]) = (list[j], list[I])
4)也可以自定义swap方法
5)swift自带的交换方法
        swap(&list[i], &list[j])

2)外层优化

当发现在某一趟排序中没有发生交换,则说明排序已经完成,所以可以在此趟排序后结束排序,在每趟排序前设置flag,当其未发生变化时,终止算法

func bubbleSort1(_ array : [Int]){
        var list = array
        //记录循环次数
        var count = 0
        for i in 0..<list.count {
            var flag = true
            count = i
            for j in i+1..<list.count{
                if list[i] > list [j] {
                    list.swapAt(i, j)
                    flag = false
                }
            }
            if flag {
                break
            }
        }
        print(list)
        print("count: ",count)
        
    }

3)内层优化

每趟排序中,最后一次发生交换的位置后面的数据均以有序,所以可以记住最后一次交换的位置来减少排序的趟数

func bubbleSort2(_ array : [Int]){
        var list = array
        //swap变量用来标记循环里最后一次交换的位置
        var swap = 0
        var k = list.count - 1
        //记录循环次数
        var count = 0
        for i in 0..<list.count {
            var flag = true
            count = i
            for j in 0..<k{
                if list[j] > list [j+1] {
                    list.swapAt(j, j+1) 
                    flag = false
                    swap = j
                }
            }
            k = swap
            if flag {
                break
            }
        }
        print(list)
        print("count: ",count)
        
    }

4)方法的使用

        print("冒泡")
        let array = [1,3,6,9,0,5,2,4,8,7]
        SortSummary.bubbleSort(array)
        SortSummary.bubbleSort1(array)
        SortSummary.bubbleSort2(array)
        print("\n")

运行结果:

冒泡
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
count:  9
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
count:  9
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
count:  4


注:可以从执行的循环次数看出,内层优化次数减少了

5、时间复杂度

1)最好的情况下 即待排序的数组本身是有序的,比较次数为n-1,没有数据交换,即O(n)

2)最坏的情况下 即待排序的数组是完全逆序的,比较次数为n*(n-1)/2,即O(n^2)

3)平均复杂度 O(n^2)

 

github代码

注:排序的具体实现代码在 SortSummary.swift 文件里 调用是在 ViewController.swift