排序算法系列——直接选择排序

前面两篇介绍了两种插入排序算法:直接插入排序和希尔排序。这篇介绍选择排序的一种:直接选择排序。从名字就可以看出直接选择排序与直接插入排序很相似,两者相同点在与都是将待排序序列分成有序区和无序区两部分,不同之处在于直接插入排序是从无序区选出一个插入到有序区合适的位置,而直接选择排序是从无序区选出最小的一个插入到有序区尾部,使得有序区保持有序。

基本思想

一组待排序的数据,首先将其划分成两部分,一部分是已排好序的,另一部分是待排序的,然后依次从待排序部分取出最小的元素插入到已排序部分的尾部,保证有序始终是已排好序的,等待排序部分全部取出放入已排序部分之后整个排序过程就完成了。 此处与直接插入排序不同之处在于,在从无序部分选择一个元素插入到有序部分时,是挑选无序部分中最小的元素,所以在挑选时需要同无序部分的每个元素进行对比,找到最小的元素。

实现要点

将待排序序列看做为无序部分(有序部分长度为0)。然后从待排序部分使用遍历比较得到最小值的位置,将其与无序部分的第一个元素进行交换(第一轮与data[0]进行交换),重复该过程直到无序部分只剩下一个元素,即完成了排序。
Java实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.vicky.sort;

import java.util.Arrays;
import java.util.Random;

/**
* <p>
* 选择排序:直接选择排序
*
* 基本思想:
* 直接选择排序同直接插入排序,也是将整个序列分为有序区和无序区,所不同的是直接播放排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有序区
* ,而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后。
*
* 时间复杂度:O(n^2)
*
* 空间复杂度:θ(1)
*
* 稳定性:不稳定
* </p>
*
* @author Vicky
* @date 2015-8-13
*/

public class StraightSelectionSort {
/**
* 排序
*
* @param data
* 待排序的数组
*/

public static <T extends Comparable<T>> void sort(T[] data) {
long start = System.nanoTime();
if (null == data) {
throw new NullPointerException("data");
}
if (data.length == 1) {
return;
}
for (int st = 0; st < data.length - 1; st++) {
int j = st + 1;
int min = st;
// 找到最小元素的位置
for (; j < data.length; j++) {
if (data[j].compareTo(data[min]) < 0) {
min = j;
}
}
// 将最小元素放到有序区尾部
if (min != st) {// 避免跟自身交换
T temp = data[st];
data[st] = data[min];
data[min] = temp;
}
}
System.out.println("use time:" + (System.nanoTime() - start) / 1000000);
}

public static void main(String[] args) {
Random ran = new Random();
Integer[] data = new Integer[100000];
for (int i = 0; i < data.length; i++) {
data[i] = ran.nextInt(10000000);
}
StraightSelectionSort.sort(data);
System.out.println(Arrays.toString(data));
}
}

效率分析

(1)时间复杂度
O(n^2)
选择排序的交换操作介于0和(n-1)次之间。选择排序的比较操作为n(n-1)/2次之间。选择排序的赋值操作介于0和3(n-1)次之间。比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+…+1=n\times(n-1)/2。交换次数O(n),最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。所以直接选择排序的时间复杂度是O(n^2)。
(2)空间复杂度
O(1)
-从空间来看,它只需要一个元素的辅助空间,用于元素的位置交换O(1)。
(3)稳定性
不稳定。
-我们假设一个序列{1,3,5,10A,10B,7},看这个数列,假设前面三个是有序区,后面三个是无序区,则无序区中最小的元素是7,和无序区的首元素交换10A交换,则可以看到序列变成了{1,3,5,7,10B,10A},然后继续,无序区就剩下{10B,10A},我们又可以看到,这里又是一个等号问题,同样,前面的交换是必然的,而后面的交换(如果等于也要交换)则不是必然的,为了减少元素交换,直接选择排序是不稳定的。
参考文章
选择排序-维基百科
排序算法的稳定性