排序先看分类
排序是数据处理中最常见的基础操作之一。目标很直接:把一组数据按关键字重新排成有序序列,升序或降序都可以。数据库优化、任务调度、数据展示里都绕不开它。
先把几组概念分清,后面看算法会省很多力气。
比较排序和非比较排序
- 比较排序:靠元素之间的大小关系决定顺序,常见的
>、<、==都属于这一类。它适用于任意可比较的数据,理论下限一般认为是 O(n log n)。 - 非比较排序:不靠比较,而是直接利用数据本身的范围、频率等特征来定位元素。它通常只适合整数或能映射成整数的场景,速度可以做到 O(n) 级别,但适用面窄。
稳定排序和非稳定排序
- 稳定排序:相等元素排序前后的相对顺序不变。多关键字排序时很有用,比如先按分数排,再按姓名排。
- 非稳定排序:相等元素的相对顺序可能被打乱。很多时候也没问题,只要主关键字排对就够了。
内部排序和外部排序
- 内部排序:数据能一次性放进内存里处理,写起来简单,速度也更快。
- 外部排序:数据太大,内存装不下,只能借助磁盘分块处理,再合并结果。它不是我们这里的重点,但实际工程里很常见。
插入排序
直接插入排序
它的思路像整理扑克牌:左边始终保持有序,每次把一个新元素插进合适的位置。
void InsertSort(int* a, int n) {
for (int i = 0; i <= n - 2; i++) {
int end = i;
int tmp = a[end + 1];
while (end >= 0) {
if (a[end] > tmp) {
a[end + 1] = a[end];
end--;
} else {
break;
}
}
a[end + 1] = tmp;
}
}
它的特点很明确:
- 时间复杂度:最坏 O(n²),最好 O(n)
- 空间复杂度:O(1)
- 稳定性:稳定
- 适合小规模数据,或者已经接近有序的数据
希尔排序
希尔排序可以看成插入排序的改进版。它先按较大的间隔分组,让远距离元素先调整位置,再逐步缩小间隔。这个思路不花哨,但在数据量上来以后比直接插入顺手得多。
void ShellSort {
gap = n;
(gap > ) {
gap = gap / + ;
( i = ; i <= n - gap - ; i++) {
end = i;
tmp = a[end + gap];
(end >= ) {
(a[end] > tmp) {
a[end + gap] = a[end];
end -= gap;
} {
;
}
}
a[end + gap] = tmp;
}
}
}


