3.1-选择排序-简单选择排序

参考链接

  • 选择排序:简单选择排序(Simple Selection Sort)
  • 白话经典算法系列之四 直接选择排序及交换二个数据的正确实现

基本思想:

直接选择排序和直接插入排序类似,都将数据分为有序区和无序区,所不同的是直接插入排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有序区,而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后。

初始值: 3  1  5  7  2  4  9  6
第一趟: 1  3  5  7  2  4  9  6
第二趟: 1  2  5  7  3  4  9  6
第三趟: 1  2  3  7  5  4  9  6
第四趟: 1  2  3  4  5  7  9  6
第五趟: 1  2  3  4  5  7  9  6
第六趟: 1  2  3  4  5  6  9  7
第七趟: 1  2  3  4  5  6  7  9
第八趟: 1  2  3  4  5  6  7  9

在简单选择排序过程中,所需移动记录的次数比较少。最好情况下,即待排序记录初始状态就已经是正序排列了,则不需要移动记录。

最坏情况下,即待排序记录初始状态是按第一条记录最大,之后的记录从小到大顺序排列,则需要移动记录的次数最多为3(n-1)。简单选择排序过程中需要进行的比较次数与初始状态下待排序的记录序列的排列情况无关。当i=1时,需进行n-1次比较;当i=2时,需进行n-2次比较;依次类推,共需要进行的比较次数是(n-1)+(n-2)+…+2+1=n(n-1)/2,即进行比较操作的时间复杂度为O(n^2),进行移动操作的时间复杂度为O(n)。

简单选择排序是不稳定排序。

算法的实现:

首先是一些方便使用的扩展方法

extension Array where Element: Comparable {
    
    func minMaxValueIndex(at starIndex: Int = 0) -> (min: Int, max: Int)? {
        if starIndex < count - 1 {
            var max = starIndex
            var min = starIndex
            
            for current in starIndex+1 ..< count {
                if self[current] > self[max] {
                    max = current
                }
                
                if self[current] < self[min] {
                    min = current
                }
                return (min, max)
            }
        }
        return nil
    }
    
    func maxValueIndex(at starIndex: Int = 0) -> Int? {
        return minMaxValueIndex(at: starIndex)?.max
    }
    func minValueIndex(starIndex: Int = 0) -> Int? {
        return minMaxValueIndex(at: starIndex)?.min
    }
    
    var maxValue: Element? {
        if let max = self.maxValueIndex() {
            return self[max]
        }
        return nil
    }
    var minValue: Element? {
        if let min = self.minValueIndex() {
            return self[min]
        }
        return nil
    }
}

最基本的选择排序

// MARK: - 最基本的选择排序
    mutating func selectSort() {
        
        /*
         1. 整个排序过程共进行n-1趟
         2. 每次循环,会找出最小的元素,与当前位置的元素交换
         3. 循环了多少次,前面就有多少元素已经排好序了,内循环只需遍历后面未排好的元素
         */
        for begin in 0 ..< count - 1 {
            //只需遍历后面未排好的元素
            //选出最小的一个数与每次循环开始位置的元素交换;
            if let min = self.minValueIndex(begin+1) {
                if self[min] < self[begin] {
                    swap(&self[begin], &self[min])
                }
            }
            print(self)
        }

    }

算法的改进(二元选择排序)

简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可。具体实现如下:

mutating func selectSortBetter() {
        /*
         1. 整个排序过程共进行n/2趟
         2. 每次循环,会找出最小和最大的元素,与起始位置的元素交换
         */
        for begin in 0 ..< count / 2 {
            //设置每躺循环的起始位置
            let end = count-1 - begin
            
            var max = begin
            var min = begin
            
            for next in begin+1 ... end {
                //选出最小元素的索引
                if self[next] < self[min] {
                    min = next
                    continue
                }
                
                if self[next] > self[max] {
                    max = next
                }
            }
            
            //先放最小的元素
            if min != begin {
                /*
                 因为会将最小元素和第一个元素交换
                 所以如果第一个元素就是最大的元素,那么max应该指向交换后的索引
                 */
                if begin == max {
                    max = min
                }
                swap(&self[begin], &self[min])
            }
            
            if max != end {
                swap(&self[end], &self[max])
            }
            
            print(self)
        }
    }

你可能感兴趣的:(3.1-选择排序-简单选择排序)