一分钟搞定基础排序算法——选择排序
选择排序可以看做是冒泡排序的一个改进型。工作原理也是非常的简单:(此处用从小到大排序举例)第一轮,整个数组从0号位开始,从左到右遍历一遍,找出最小的元素,将其放在数组的0号位。第二轮,从1号位开始遍历一遍,找出最小值,将其放在数组的1号位。以此类推直到结束。就完成了选择排序。
尝试实现
如上图所示,有一个待排序的数组nums。按开头时讲述的算法步骤。第一趟,从0号位开始我们从左到右遍历,找出最小值。此时准备3个指针。i直接指向0号位,标记此时的未排序数组的第一个位置。index,指向找到的最小值(开始时暂定0号位就是最小值)。j作为游标,从左到右开始遍历。因为0号位已经被标记,所以j指针从i+1位置开始。
首次比较nums[j] < nums[index],index指向j的位置。j继续向右遍历。结果如下图所示。
这时比较i和index的值,发现不是同一值,双方值交换。
然后如此类推开始第二趟遍历。
而且这是我们也发现了一个规律,当有N个数字时,第N趟时,j指向为n,已经发生数组越界。所以当有N个数字时,n-1趟就能完成排序。
用代码实现:
public static void selectionSort(int[] nums) {
if (null == nums || nums.length < 2) {
return;
}
//N个数字,n-1趟即可完成排序
for (int i = 0; i < nums.length - 1; i++) {
//开始时,默认i指向的为最小值
int index = i;
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] < nums[index]) {
index = j;
}
}
if(index != i){
int temp = nums[i];
nums[i] = nums[index];
nums[index] = temp;
}
}
}
算法分析
时间复杂度
选择排序时间复杂度和冒泡类似:
最好情况
数组已经是一个排好序的数组,一趟遍历即可完成。算法复杂度为O(n)
最坏情况
队列逆序排列,需要N-1趟进行排序。并且每次要进行N-i次的比较才能完成。
i的取值为1<=i<=N-1。时间复杂度O(n^2)
平均情况
数组乱序排列时,数组的平均复杂度为O(n^2)
这里需要注意的是,虽然选择排序和冒泡排序的时间复杂度一样,但是选择排序进行的交换操作少,最多发生 N - 1次交换。冒泡排序最坏的情况下要发生
N^2 /2
的交换操作。因此可以得出结论,选择排序的性能略优于冒泡排序。
空间复杂度
空间复杂度和冒泡一样,因为交换的时候需要一个额外的空间来辅助完成元素交换动作。所以空间复杂度为O(1)。
算法稳定性
值得注意的是选择排序是不稳定的排序算法。
我们对初始时的数组做个简单的修改。如下图所示。有两个13,分别为绿色和黄色。
第一趟完成后,结果会变为:
这时发现两个13的相对顺序已经发生了改变。所以说选择排序不是一个稳定的排序算法。