排序算法系列文章
排序(一):冒泡排序
排序(二):选择排序
排序(三):堆排序
排序(四):插入排序
排序(五):二分搜索
排序(六):归并排序
排序(七):快速排序
排序(八):希尔排序
选择排序(Selection Sort)
算法步骤(升序)
①从序列中找出最大的那个元素,然后与最末尾的元素交换位置;
②执行完一轮后,最末尾的那个元素就是最大的元素;
③忽略①中曾经找到的最大元素,重复执行步骤①
代码实现
public class SelectionSort {
public static void main(String[] args) {
int[] array = {10,9,19,28,37,34,5};
for (int end = array.length - 1; end > 0; end--) {
int maxIndex = 0;
for (int begin = 1; begin <= end; begin++) {
if (array[maxIndex] <= array[begin]){
maxIndex = begin;
}
}
int tmp = array[maxIndex];
//此时的end就是下一轮循环的索引
array[maxIndex] = array[end];
array[end] = tmp;
}
//输出打印
for (int i = 0; i < array.length; i++){
System.out.println(array[i] + "_");
}
}
}
关于
if (array[maxIndex] <= array[begin])
代码中, 比较符号使用<
和<=
的说明:
- 为了让选择排序是稳定的排序算法, 此时比较的时候要使用
<=
符号- 比如有序列 (a)10, (b)8, ©10, (d)9 前面的括号表示它们的索引。
- 假如说使用的是
<
号, 当(a)10作为最大元素进行比较的时候, 和©10进行比较时,判断不会通过,所以第一轮循环之后, 最大的元素依然是(a)10。此时就要和末尾元素(d)9交换位置, 此时(a)10就跑到序列的最后了(变为(d)10).
之后的循环它也不会参与, 所以下轮循环©10就在它的前面了。之前(a)10在©10的前面; 排完序之后, (a)10变(d)10,
跑到了©10的后面. 此时显然不符合排序的稳定性。- 使用
<=
号, 当第一轮循环(a)10与©10比较, 它们相等, 此时要将©10的索引c变为maxIndex, 接着比较, 第一轮比较完©10就跑到序列的最后了; 第一轮比较后的顺序: (a)10, (b)8, ©(9), (d)10.
下次循环比较之后, (a)10就会和©9交换位置, 变为(a)9, (b)8, ©10, (d)10.
排序之前(a)10就在©10的前面, 排序之后它们的顺序还是一致的. 此时的选择排序就是稳定的
复杂度
- 选择排序的交换次数要远远少于冒泡排序,平均性能优于冒泡排序。
- 最好,最坏,平均时间复杂度:O(n^2),空间复杂度:O(1)。
- 属于不稳定排序。
算法优化
- 选择排序每次循环中都需要找出最大的元素与最后位置的元素进行交换,可以使用
大顶堆
来实现查找最大元素,可以将查找元素的时间复杂度由O(n)降低为O(logn),其实就是堆排序
。