会打扑克就会选择排序
会打扑克就会选择排序
选择排序很像一小部分人打扑克牌时(因为大部人是另外一种方式,对应我们常见的另外一种排序了),把牌从左到右扫描,选出最小的一张牌,放到最左边,然后从第二张牌继续扫描第二张小的牌,放到第二小的位置,依次进行下去。。。这个画面感是不是很熟悉。没错,这在程序中就是选择排序,是不是相当的简单。
定义
选择排序是一种很简单直观的排序算法, 属于选择类排序算法。
选择排序,一般我们指的是简单选择排序,也可以叫直接选择排序,它不像冒泡排序一样相邻地交换元素,而是通过选择最小的元素,每轮迭代只需交换一次。虽然交换次数比冒泡少很多,但效率和冒泡排序一样的糟糕。
动图展示
思路
设左边为有序区,右边乱序区。从右边剩下的乱序数字中找最小,放到左边。(反过来也是可以的,这里我们只讲解这种从小到大的情况)
具体操作: 多次比较,一次交换。 每次从右边剩余数字中选最小,与乱序区最左边的元素交换,使左边有序区边界右移。
文字叙述过程
参照上面的动图演示,我们也很容易给出过程的文字描述:
-
第1趟比较:拿第1个元素依次和它后面的每个元素进行比较,如果第1个元素大于后面某个元素,交换它们,经过第1趟比较,数组中最小的元素被选出,它被排在第一位 -
第2趟比较:拿第2个元素依次和它后面的每个元素进行比较,如果第2个元素大于后面某个元素,交换它们,经过第2趟比较,数组中第2小的元素被选出,它被排在第二位 -
...... -
第n-1趟比较:第n-1个元素和第n个元素作比较,如果第n-1个元素大于第n个元素,交换它们
实现
也许你想说,"说了这么多,还说很简单,你倒是整一个啊!", 好的,这就安排上。
算法安排
package sort
func SelectSort(array []int) {
arrayLen := len(array)
// 进行N-1轮迭代
for i := 0; i < arrayLen-1; i++ {
// 最小元素的索引位
minIndex := i
// 记录下最小数
min := array[i]
for j := i + 1; j < arrayLen; j++ {
if array[j] < min {
// 变更最小数和最小数下标
min = array[j]
minIndex = j
}
}
// 进行元素位置交换
if minIndex != i {
array[i], array[minIndex] = array[minIndex], array[i]
}
}
}
一种优化思路
这边其实还有一种优化思路就是: 我们一轮同时进行最小值和最大值的扫描,然后分别和最前面和最后面的元素进行交换,这样将会使我们的复杂度少一半。
代码安排上:
package sort
func SelectSortOpt1(array []int) {
arrayLen := len(array)
// 进行N/2轮迭代
for i := 0; i < arrayLen/2; i++ {
// 最小元素的索引位
minIndex := i
// 最大元素的索引位
maxIndex := i
// 记录下最小数
min := array[i]
// 记录下最大数
max := array[i]
for j := i + 1; j < arrayLen-i; j++ {
if array[j] < min {
// 变更最小数和最小数下标
min = array[j]
minIndex = j
}
if array[j] > max {
// 变更最大数和最大数下标
max = array[j]
maxIndex = j
}
}
// 进行元素位置交换
if minIndex != i {
array[i], array[minIndex] = array[minIndex], array[i]
}
if maxIndex != arrayLen-i-1 {
array[arrayLen-i-1], array[maxIndex] = array[maxIndex], array[arrayLen-i-1]
}
}
}
复杂度
时间复杂度
首先,为了在第 1 轮找到最小的数字,需要从左往右确认数列中的数字,只要查询 n 个数 字即可。在接下来的第 2 轮中,需要从 n -1 个数字中寻找最小值,所以需要查询 n -1 个数字。将这个步骤进行到第 n 轮的时候,需要查询的次数如下。
n+( n- 1)+(n-2)+…3+2 +1=n(n+1)/2≤ n^2
平均时间复杂度 О(n²) 最坏时间复杂度 О(n²) 最优时间复杂度 О(n²)
空间复杂度
空间复杂度:O(1),只需要一个附加程序单元用于交换
稳定性
稳定性:选择排序是不稳定的排序算法,因为无法保证值相等的元素的相对位置不变。
例如: [3, 4, 3, 1]这个数组,第一次交换,第一个3和1交换位置,此时原来两个3的相对位置发生了变化。
总结
选择排序可以说是表现最稳定的排序算法之一,因为最优最坏的时间复杂度都是都是O(n2)。但唯一的好处可能就是不占用额外的内存空间了吧, 空间复杂度为O(1)。选择排序按讲应该也是最容易想到的一种排序算法,因为我们生活中这样的实例太多了,比比皆是。
参阅:
选择排序
图解排序算法及实现——选择排序(Selection sort)