你心爱的各种排序算法,用 C 语言实现。
我们下面将要实现的算法,全部准循这个接口:
// sort 对数组 A 的前 n 个元素进行原址排序
typedef void (*sort)(int A[], int n);
直接插入排序
遍历,往前找到合适的位置,逐个元素后移腾出空间,插入进去。
复杂度:
- 时间 O ( n 2 ) O(n^2) O(n2)
- 空间 O ( 1 ) O(1) O(1)
void
insert_sort(int A[], int n)
{
for (int i = 0; i < n; ++i) {
int curr = A[i];
int j = i - 1;
while (j >= 0 && curr < A[j]) {
A[j + 1] = A[j];
--j;
}
A[j + 1] = curr;
}
}
二分插入排序
就是直接插入里往前找合适位置那里用个二分查找。
复杂度:
- 时间:较好 O ( n log ( n ) ) O(n \log(n)) O(nlog(n)),较坏 O ( n 2 ) O(n^2) O(n2),平均 O ( n 2 ) O(n^2) O(n2)
- 空间 O ( 1 ) O(1) O(1)
void
binary_insert_sort(int A[], int n)
{
for (int i = 0; i < n; ++i) {
int curr = A[i];
// 二分查找
int l = 0, r = i - 1;
while (r >= 0 && l < i && l <= r) {
int m = (l + r) / 2;
if (curr < A[m]) {
r = m - 1;
} else {
l = m + 1;
}
}
// 后移
for (int j = i - 1; j >= l; --j) {
A[j + 1] = A[j];
}
// 插入
A[l] = curr;
}
}
Shell 排序
递减增量(gap)的排序算法(非稳定)。就是分好几轮排序,每轮里在隔 gap 个的序列里调整插入。
空间复杂度是 O ( 1 ) O(1) O(1),时间复杂度依赖于步长序列。
void
shell_sort(int A[], int n)
{
int gap;
foreach_gaps(gap, n, {
// 里面就是个插入排序:
for (int i = gap; i < n; i++) {
int curr = A[i];
int j = i - gap;
for (; j >= 0 && A[j] > curr; j -= gap) {
A[j + gap] = A[j];
}
A[j + gap] = curr;
}
});
}
foreach_gaps
遍历增量序列,将步长值放到 gap 中。可以选用多种步长序列(注意步长最后一步务必为 1):
-
Shell 步长序列: n / 2 i n/2^i n/2i,最坏情况下时间复杂度