插入排序
核心思路是逐步构建有序序列。就像整理扑克牌,每次摸到的新牌都要插到手里已排好序的牌堆里合适的位置。
将数组分为'已排序'和'未排序'两部分,初始时已排序部分只包含第一个元素。每次从未排序部分取出第一个元素,向前插入到已排序序列中的正确位置,使得插入后的序列依然保持有序。重复这个过程,直到所有元素都被插入。
void InsertSort(int* a, int n) {
// 遍历未排序元素(从第 2 个元素开始)
for (int i = 1; i < n; i++) {
int end = i - 1;
int tmp = a[i];
// 向前查找合适位置,大于 tmp(降序)则后移
while (end >= 0) {
if (a[end] < tmp) {
a[end + 1] = a[end];
end--;
} else {
break;
}
}
a[end + 1] = tmp;
}
}
时间复杂度方面,最坏情况下比较次数为等差数列求和,即 O(N^2);但在数组已有序的情况下,每个元素仅需比较 1 次,可优化至 O(N)。空间复杂度为 O(1),且排序是稳定的,因为相等元素的相对位置在排序前后保持不变。

希尔排序
希尔排序的核心思想是分组插入排序,逐步缩小增量。将整个待排序数组按照某个增量(步长)分割成若干个子序列,对每个子序列分别进行插入排序,让数组整体变得'基本有序'。然后逐步缩小增量,重复上述操作。当增量缩小到 1 时,整个数组就变成了一个子序列,此时再进行一次插入排序,数组就完全有序了。
这就像先把乱序的扑克牌按花色分组整理,再按点数细分整理,最后整体微调。大增量时元素移动跨度大,能快速把乱序的数组变得大致有序;小增量时数组已经基本有序,插入排序的效率会非常高。
void ShellSort(int* a, int n) {
int gap = n;
while (gap > 1) {
gap = gap / 3 + 1;
/*-------------一组排完排另一组-------------*/
( j = ; j < gap; j++) {
( i = ; i < n - gap; i += gap) {
end = i;
tmp = a[i + gap];
(end >= ) {
(tmp > a[end]) {
a[end + gap] = a[end];
end -= gap;
} {
;
}
}
a[end + gap] = tmp;
}
}
}
}






