定义

选择排序(Selection Sort)是一种简单直观的 原地 比较排序算法:每轮在未排序区间中选出 极值(最小或最大),将其换到区间一端,使已排序部分逐步扩展。

特性:平均 · 最好 · 最坏 · 空间 · 原地 · 不稳定

过程

每趟扫描未排序区间,找出其中的 极值 并与区间边界元素交换——该极值就此就位,已排序部分扩展一位。每趟至少确定一个元素的位置,因此 个元素最多进行 趟即可排完。

选择排序动画

性质

稳定性

选择排序是 不稳定 排序算法。每趟将未排序区间的 极值 与区间边界元素 互换,两者通常 并不相邻;边界元素落位时会 跨过 区间内的其他元素。若途中存在与边界元素 键相等 的对象,一次交换就可能打乱它们的相对顺序。相等时即便在选取极值时有固定取舍规则,也 不能 避免这种跨换。

以升序为例,[3a, 3b, 1]3a3b 值均为 3):

趟次操作结果
第 1 趟极值 1 与边界 3a 交换[1, 3b, 3a]
第 2 趟极值 3b 已在边界,无需交换[1, 3b, 3a]

输入时 3a3b 前面,排序后 3b3a 前面,相对顺序被破坏。

时间复杂度

情况复杂度说明
最好比较次数固定,已有序时仍须扫完全部区间
最坏 次比较
平均随机数据下比较次数同阶

比较次数无法省略,但交换次数至多 次。可在交换前判断极值是否已在区间边界——已在则跳过;对已有序输入,交换次数可降至

空间复杂度

。原地排序,仅使用常数个辅助变量。

代码实现

基础写法

i != min 判断极值是否已在边界,避免无意义的自交换:

static void swap(int* a, int* b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
 
void selection_sort(int* arr, int len) {
    for (int i = 0; i < len; i++) {
        int min = i;
        for (int j = i + 1; j < len; j++) {
            if (arr[j] < arr[min]) min = j;
        }
 
        if (i != min) swap(arr + i, arr + min);
    }
}

参考阅读