选择排序

1067 字
5 分钟
选择排序

选择排序#

选择类排序的核心操作:每趟选出最小(或最大)元素放到最终位置。代表算法有简单选择排序堆排序

简单选择排序#

核心思想#

  • 在未排序区间 [i, n-1] 中找到最小元素的下标 min
  • a[min]a[i] 交换,a[i] 到达最终位置
  • 每轮确定一个元素,共需 n-1 轮

代码实现#

void SelectionSort(int a[], int n) {
for (int i = 0; i < n - 1; i++) {
int min = i;
for (int j = i + 1; j < n; j++)
if (a[j] < a[min]) min = j;
if (min != i) {
int tmp = a[i];
a[i] = a[min];
a[min] = tmp;
}
}
}

复杂度#

指标说明
比较次数n(n-1)/2与初始序列无关 ⭐
最好交换0已有序
最坏交换n-1每轮都需交换
时间复杂度O(n²)所有情况
空间O(1)
稳定性不稳定反例:{2, 2, 1}

⚠️ 易错:简单选择排序是不稳定的。反例 {5a, 5b, 3},第一趟选出 3 与 5a 交换 → {3, 5b, 5a},相对顺序颠倒。

⚠️ 易错:比较次数始终为 n(n-1)/2,与初始序列无关。408 常考”以下哪种排序的比较次数与初始序列无关”。

与冒泡排序对比#

对比项简单选择冒泡
比较次数固定 n(n-1)/2最好 O(n),最坏 O(n²)
交换次数最多 n-1最坏 O(n²)
对输入敏感
稳定性不稳定稳定

堆排序#

O(1) 空间的 O(n log n) 排序#

堆排序只用 O(1) 额外空间就能保证最坏 O(n log n)——快排做不到。但 cache 不友好,实际速度常输给快排。

堆的概念#

堆是一棵完全二叉树

  • 大顶堆(最大堆):每个结点 ≥ 其左右孩子 A[i] ≥ A[2i+1]A[i] ≥ A[2i+2]
  • 小顶堆(最小堆):每个结点 ≤ 其左右孩子 A[i] ≤ A[2i+1]A[i] ≤ A[2i+2]

下标关系(数组从 0 开始)

关系公式
结点 i 的父结点(i - 1) / 2
左孩子2i + 1
右孩子2i + 2

建堆过程#

自底向上的向下调整(sift-down):从最后一个非叶子结点(下标 n/2-1)开始,依次向前对每个结点执行 sift-down。

void SiftDown(int A[], int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && A[left] > A[largest]) largest = left;
if (right < n && A[right] > A[largest]) largest = right;
if (largest != i) {
swap(A[i], A[largest]);
SiftDown(A, n, largest);
}
}
void BuildMaxHeap(int A[], int n) {
for (int i = n / 2 - 1; i >= 0; i--)
SiftDown(A, n, i);
}

⚠️ 易错:建堆的时间复杂度是 O(n),不是 O(n log n)。大部分结点位于底层,调整距离短,总和为 O(n)。

排序过程#

void HeapSort(int A[], int n) {
BuildMaxHeap(A, n);
for (int i = n - 1; i > 0; i--) {
swap(A[0], A[i]); // 堆顶与末尾交换
SiftDown(A, i, 0); // 调整堆顶,堆规模减 1
}
}

堆的插入与删除#

操作方法时间
插入追加到末尾,向上调整(sift-up)O(log n)
删除堆顶与末尾交换,规模减 1,sift-downO(log n)

⚠️ 注意:用 sift-up 逐个插入建堆的时间复杂度为 O(n log n),不如自底向上 sift-down 的 O(n)。

复杂度#

指标
最好时间O(n log n)
最坏时间O(n log n)
平均时间O(n log n)
空间O(1)
稳定性不稳定

Top-K 问题#

从 n 个元素中选出前 K 大/小:

  • 建一个大小为 K 的小顶堆(求前 K 大)或大顶堆(求前 K 小)
  • 扫描剩余元素,比堆顶大则替换并调整
  • 时间复杂度:O(n log K)

考研高频考点#

简单选择排序#

  • ⭐ 比较次数始终为 n(n-1)/2,与初始序列无关
  • ⭐ 不稳定排序,反例 {2, 2, 1}
  • ⭐ 时间复杂度始终 O(n²)

堆排序#

  • ⭐ 建堆复杂度 O(n) 而非 O(n log n)(高频陷阱)
  • ⭐ 不稳定排序
  • ⭐ 空间复杂度 O(1),原地排序
  • ⭐ 父子结点下标关系(从 0 / 从 1 开始)
  • ⭐ Top-K 问题的堆解法
  • 给定序列判断是否为堆 / 画出建堆中间过程
  • 堆排序 vs 快排 vs 归并的综合比较

关联页面#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

选择排序
https://lingluoa.icu/posts/sorting-selection/
作者
lingluoa
发布于
2026-07-07
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
lingluoa
Hello, I'm lingluoa.
公告
欢迎来到我的博客!不定期更新中。
文章目录
标签
站点统计
文章
53
分类
9
标签
75
总字数
175,771
运行时长
0
最后活动
0 天前
站点信息
构建平台
ESA Pages
博客版本
Firefly v6.15.6
文章许可
CC BY-NC-SA 4.0