4.1.2 简单选择排序
简单选择排序是最常用的选择类排序算法。对一个拥有
n
n
n个元素的序列,简单选择排序会进行n-1
趟操作,每一趟操作选出当前无序序列中最小(或最大)的元素,然后将其与无序序列的第一个(或最后一个)元素进行交换,这样最小(或最大)的元素就准确到位。
这么说可能有些抽象,我们来看一个小例子:从小到大排序{49, 38, 68, 97, 76, 13, 27, 49}。当前情况下,整个序列都是无序的。
无序 | |||||||
49 | 38 | 68 | 97 | 76 | 13 | 27 | 49 |
- 第一趟
简单选择排序算法会遍历整个无序序列,通过比较,找出最小的元素在序列中的位置。然后,将最小的元素和无序序列中的第一个元素进行位置调换。这里13是最小的元素,第一趟操作之后被排在了它应该在的位置,可以说它现在是有序的了。
有序 | 无序 | ||||||
13 | 38 | 68 | 97 | 76 | 49 | 27 | 49 |
- 第二趟
之后,仍然遍历整个无序序列,找到当前的最小元素27,将其与无序序列的第一个元素进行位置调换。{13, 27}现在有序。
有序 | 无序 | ||||||
13 | 27 | 68 | 97 | 76 | 49 | 38 | 49 |
以此类推,我们一共会进行7趟操作,因为最后一个元素不需要再进行多余的比较,已经在它该在的位置上了,可以直接将它添加到有序中。所以对于简单选择排序算法而言,n个元素的无序序列要进行n-1趟操作。代码如下:
#include <cstdio>
int main(){
int a[10] = {49, 38, 68, 97, 76, 13, 27, 49};
// 记录每一趟无序序列中最小元素的位置
int k;
// 核心代码,进行n-1趟操作
// 这里的8是序列元素个数,也就是上面的n,这么写方便理解
// 顺便说一句,即使这里写成i<8也是可以的,也就是常说的n趟操作
// 因为进行第n趟操作时,内层循环设定的初始是i+1,会根据条件自动跳出循环
// 所以其实第n趟操作没有进行比较,且自己跟自己进行了个交换,感觉这样没必要
for(int i=0; i<8-1; i++){
// 存储无序序列中的第一个元素位置
k = i;
// 关键代码,找出无序序列中最小的元素
// 从无序序列中的第二个元素开始
for(int j=i+1; j<8; j++){
if(a[j] < a[k]){
k = j;
}
}
// 将无序序列中的最小元素与无序序列中的第一个元素进行交换
int temp = a[k];
a[k] = a[i];
a[i] = temp;
}
// 输出排列好的序列
for(int i=0; i<8; i++){
printf("%d", a[i]);
if(i<8-1){
printf(" ");
}
}
printf("\n");
return 0;
}
时间复杂度
:将主要代码内层循环中的比较操作看作基本操作,考虑最坏情况。算法第一趟操作进行了n-1次比较,第二趟进行了n-2次比较,以此类推,第n-1趟操作进行了1次比较。于是总的操作次数为
(
1
+
(
n
−
1
)
)
∗
(
n
−
1
)
2
=
n
2
−
n
2
\frac{(1+(n-1))*(n-1)}{2} = \frac{n^2-n}{2}
2(1+(n−1))∗(n−1)=2n2−n,简单选择排序的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)。
空间复杂度
:算法所需的辅助存储空间不随规模
n
n
n的变化而变化,是个常量,所以简单选择排序的空间复杂度为
O
(
1
)
O(1)
O(1)。