首页 / 算法动画 / 选择排序

选择排序动画

每轮从未排序区间选出最小值,放到已排序区间末尾

时间复杂度 O(n²) 空间复杂度 O(1) 不稳定
动画加载中…

算法原理

选择排序(Selection Sort)的策略最「朴素」:每一轮从未排序区间里选出最小的元素,直接放到未排序区间的开头,已排序前缀就增长一格。它不像冒泡那样频繁交换——每轮只在最后做至多一次交换

对长度为 n 的序列,执行过程是:

  1. 第 1 轮:扫描 a[0..n],记录最小值下标 min_idx,若最小值不在头部就与 a[0] 交换;
  2. 第 2 轮:对 a[1..n] 重复,把次小值换到下标 1;
  3. 以此类推,每轮确定一个位置的最终值,n-1 轮后整体有序。

动画怎么看

柱子颜色就是状态语言(页面右侧也有图例):

  • 金色柱:当前轮已发现的最小值 a[min_idx]——扫描过程中它会不断被更小的元素取代;
  • 红色柱:本轮结束时正在与 a[i] 交换的一对元素;
  • 绿色柱:已就位的前缀 a[0..i],从左往右生长;
  • 蓝色柱:尚未处理的元素。

动画下方有一行实时解说(如 第 2 轮:扫描 a[3..] 找最小,a[3] = 9 与当前最小 a[0] = 38 比较本轮最小 a[1] = 17,与 a[0] = 38 交换),结束时汇总总比较次数与交换次数。可以直观看到它的特点:比较次数很多(每轮扫完全程)、交换次数极少(每轮至多 1 次)——这正是它与冒泡排序最大的区别。

复杂度分析

项目复杂度说明
平均/最坏/最好时间O(n²)无论输入是否有序,比较次数固定为 n(n-1)/2
空间O(1)只需记录最小值下标,原地排序
交换次数最多 n-1 次若「写入」代价远高于「比较」(如闪存场景),这是它的独特优势
稳定性不稳定跨距离交换会把相等元素的相对次序打乱(如 [2₁, 2₂, 1] 一轮就变 [1, 2₂, 2₁]

C++ 参考代码

#include <iostream>
#include <vector>
#include <utility>  // std::swap
using namespace std;

// 选择排序:每轮选出未排序区间的最小值放到 a[i]
void selectionSort(vector<int>& a) {
    int n = a.size();
    for (int i = 0; i < n - 1; i++) {
        int minIdx = i;
        for (int j = i + 1; j < n; j++) {
            if (a[j] < a[minIdx]) minIdx = j;   // 记录更小值的下标
        }
        if (minIdx != i) swap(a[i], a[minIdx]); // 每轮至多交换一次
    }
}

int main() {
    vector<int> a = {5, 2, 9, 1, 7, 3, 8, 4};
    selectionSort(a);
    for (int x : a) cout << x << ' ';   // 输出:1 2 3 4 5 7 8 9
    cout << endl;
    return 0;
}

什么时候用选择排序

选择排序比较次数恒为 O(n²),且不稳定,通用场景不如插入排序。但它的交换次数是所有朴素排序里最少的(至多 n-1 次),在「比较便宜、写入昂贵」的存储介质上反而占优;「每轮选一个最值」的框架也是优先队列 / 堆排序思想的雏形,CSP-J 阶段常以「每次取最小」「约瑟夫式挑选」等模拟题形式出现。