1.1-交换排序-冒泡

参考链接

  • 交换排序:冒泡排序(Bubble Sort)
  • 白话经典算法系列之一 冒泡排序的三种实现

基本思想

以从小到大排序举例

  1. 从第一个元素开始依次比较数组相邻2个数,直到N-i,如果前面的元素大于后面的元素,就将二个元素交换
  2. �i加1并重复步骤1,这样每次最大的元素就会被放到末尾
  3. 直到最后只剩前2个数做比较
初态 第1趟 第2趟 第3趟 第4趟 第5趟 第6趟 第7趟
 49   38   38   38    38   13   13   13
 38   49   49   49    13   27   27   27 
 65   65   65   13    27   38   38
 97   76   13   27    49   49
 76   13   27   49    49
 13   27   49   65
 27   49   76 
 49   97

算法的实现

// MARK: - 最基本的冒泡排序
extension Array where Element: Comparable {
    mutating func bubbleSort1() {
        /*
         1. 整个排序过程共进行n-1趟
         2. 每次循环,会找出最大的元素,放到末尾
         3. 循环了多少次,末尾就有多少元素已经排好序了,内循环只需遍历前面未排好的元素
         */
        let totalLoop = count - 1
        
        for loopCount in 0 ..< totalLoop {
            //只需遍历前面未排好的元素
            for current in 0 ..< totalLoop - loopCount {
                let next = current + 1
                //比较相邻的2个元素,并把较大的元素往后面放
                if self[current] > self[next] {
                    swap(&self[current], &self[next])
                }
            }
            print(self)
        }
    }
}

冒泡排序算法的改进

定义一个标志性变量exchange,表示某一趟排序过程中是否有数据交换,如果没有,则说明数据已经按要求排列好,可立即结束排序

mutating func bubbleSortBetter1() {
        
        /*
         1. 整个排序过程共最多进行n-1趟,当没有元素交换时,就已经全部排好序了
         2. 每次循环,会找出最大的元素,放到末尾
         3. 循环了多少次,末尾就有多少元素已经排好序了,内循环只需遍历前面未排好的元素
         
         可以相对减少循环总次数
         */
        let totalLoop = count - 1
        for loopCount in 0 ..< totalLoop {
             var sorted = true
            
            for current in 0 ..< totalLoop - loopCount {
                let next = current + 1
                //比较相邻的2个元素,并把较大的元素往后面放
                if self[current] > self[next] {
                    swap(&self[current], &self[next])
                    sorted = false//这次循环进行了数据交换,说明没排好序
                }
            }
            print(self)
            //如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序
            if sorted { break }
        }
    }

再做进一步的优化。如果有100个数的数组,仅前面10个无序,后面90个都已排好序且都大于前面10个数字,那么在第一趟遍历后,最后发生交换的位置必定小于10,且这个位置之后的数据必定已经有序了,记录下这位置,第二次只要从数组头部遍历到这个位置就可以了。

mutating func bubbleSortBetter2() {
        
        /*
         1. unSortedIndex记录每趟排序中最后一次进行交换的位置。
         2. 每次循环,只会对0~unSortedIndex进行比较,并找出最大的元素,放到末尾
         3. 当没有元素交换时,表示已经排好序,所以整个排序过程共最多进行n-1趟
         
         可以在上面基础上再相对减少循环总次数
         */
        var unSortedIndex = count - 1
        var sorted = false
        
        while !sorted {
            //如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序
            sorted = true
            
            //每次循环,只会对0~unSortedIndex进行比较
            for current in 0 ..< unSortedIndex {
                let next = current + 1
                //比较相邻的2个元素,并把较大的元素往后面放
                if self[current] > self[next] {
                    swap(&self[current], &self[next])
                    unSortedIndex = current //记录每趟排序中最后一次进行交换的位置
                    sorted = false
                }
            }
            print(self)
        }
    }

传统冒泡排序中每一趟排序操作只能找到一个最大值或最小值,我们考虑利用在每趟排序中进行正向和反向两遍冒泡的方法一次可以得到两个最终值(最大者和最小者) , 从而使排序趟数几乎减少了一半。

但总次数其实是一样的,有个卵用,不实现了

你可能感兴趣的:(1.1-交换排序-冒泡)