intMedianOfThree(int* arr, int left, int right) {
int mid = left + (right - left) / 2;
if (arr[left] > arr[mid]) {
if (arr[mid] > arr[right]) return mid;
elseif (arr[left] > arr[right]) return right;
elsereturn left;
} else {
if (arr[left] > arr[right]) return left;
elseif (arr[mid] > arr[right]) return right;
elsereturn mid;
}
}
4.2.1 Hoare 版本
int _QuickSort_Hoare(int* arr, int left, int right) {
int medianIndex = MedianOfThree(arr, left, right);
Swap(&arr[left], &arr[medianIndex]);
int keyi = left;
++left;
while (left <= right) {
while (left <= right && arr[right] > arr[keyi]) { right--; }
while (left <= right && arr[left] < arr[keyi]) { left++; }
if (left <= right) { Swap(&arr[left++], &arr[right--]); }
}
Swap(&arr[right], &arr[keyi]);
return right;
}
4.2.2 挖坑法
int _QuickSort_Hole(int* arr, int left, int right) {
int medianIndex = MedianOfThree(arr, left, right);
Swap(&arr[left], &arr[medianIndex]);
int key = arr[left];
int hole = left;
while (left < right) {
while (left < right && arr[right] > key) { right--; }
arr[hole] = arr[right]; hole = right;
while (left < right && arr[left] < key) { left++; }
arr[hole] = arr[left]; hole = left;
}
arr[hole] = key;
return hole;
}
4.2.3 Lomuto 前后指针
int _QuickSort_Lomuto(int* arr, int left, int right) {
int medianIndex = MedianOfThree(arr, left, right);
Swap(&arr[left], &arr[medianIndex]);
int prev = left;
int cur = left + 1;
int key = left;
while (cur <= right) {
if (arr[cur] < arr[key] && (++prev) != cur) {
Swap(&arr[prev], &arr[cur]);
}
cur++;
}
Swap(&arr[key], &arr[prev]);
return prev;
}
4.2.4 非递归实现
非递归版本求基准值需要借助栈这个数据结构。
voidQuickSortNonR(int* arr, int left, int right) {
ST st;
STInit(&st);
StackPush(&st, right);
StackPush(&st, left);
while (!StackEmpty(&st)) {
int begin = StackTop(&st); StackPop(&st);
int end = StackTop(&st); StackPop(&st);
int prev = begin;
int cur = begin + 1;
int keyi = begin;
while (cur <= end) {
if (arr[cur] < arr[keyi] && ++prev != cur) {
Swap(&arr[cur], &arr[prev]);
}
cur++;
}
Swap(&arr[keyi], &arr[prev]);
keyi = prev;
if (keyi + 1 < end) {
StackPush(&st, end);
StackPush(&st, keyi + 1);
}
if (keyi - 1 > begin) {
StackPush(&st, keyi - 1);
StackPush(&st, begin);
}
}
STDestroy(&st);
}
4.2.5 三路划分
三路划分快速排序是快速排序的优化版本,特别适合处理包含大量重复元素的数组。
void _QuickSort_3Way(int* arr, int left, int right, int* lt, int* gt) {
if (left >= right) return;
int medianIndex = MedianOfThree(arr, left, right);
Swap(&arr[left], &arr[medianIndex]);
int key = arr[left];
int cur = left + 1;
*lt = left;
*gt = right;
while (cur <= *gt) {
if (arr[cur] < key) {
Swap(&arr[cur], &arr[*lt + 1]);
(*lt)++;
cur++;
} elseif (arr[cur] > key) {
Swap(&arr[cur], &arr[*gt]);
(*gt)--;
} else {
cur++;
}
}
Swap(&arr[left], &arr[*lt]);
}
voidQuickSort_3Way(int* arr, int left, int right) {
if (left >= right) return;
int lt, gt;
_QuickSort_3Way(arr, left, right, <, >);
QuickSort_3Way(arr, left, lt - 1);
QuickSort_3Way(arr, gt + 1, right);
}
/**
* 归并排序的递归辅助函数
* 时间复杂度:O(n log n)
* 空间复杂度:O(n)
* 稳定性:稳定
*/void _MergeSort(int* arr, int left, int right, int* tmp) {
if (left >= right) return;
int mid = (left + right) / 2;
_MergeSort(arr, left, mid, tmp);
_MergeSort(arr, mid + 1, right, tmp);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = begin1;
while (begin1 <= end1 && begin2 <= end2) {
if (arr[begin1] < arr[begin2]) { tmp[index++] = arr[begin1++]; }
else { tmp[index++] = arr[begin2++]; }
}
while (begin1 <= end1) { tmp[index++] = arr[begin1++]; }
while (begin2 <= end2) { tmp[index++] = arr[begin2++]; }
for (int i = left; i <= right; i++) { arr[i] = tmp[i]; }
}
voidMergeSort(int* arr, int n) {
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL) return;
_MergeSort(arr, 0, n - 1, tmp);
free(tmp);
}
6. 计数排序
计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。
/**
* 计数排序 - 非比较型排序算法
* 时间复杂度:O(n + k)
* 空间复杂度:O(k)
* 稳定性:不稳定
*/voidCountSort(int* arr, int n) {
int max = arr[0], min = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
int range = max - min + 1;
int* count = (int*)malloc(sizeof(int) * range);
if (count == NULL) { perror("malloc fail!"); exit(1); }
memset(count, 0, range * sizeof(int));
for (int i = 0; i < n; i++) { count[arr[i] - min]++; }
int index = 0;
for (int i = 0; i < range; i++) {
while (count[i]--) { arr[index++] = i + min; }
}
free(count);
}
/**
* 稳定版本的计数排序
*/voidStableCountSort(int* arr, int n) {
int max = arr[0], min = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
int range = max - min + 1;
int* count = (int*)calloc(range, sizeof(int));
if (count == NULL) exit(1);
for (int i = 0; i < n; i++) count[arr[i] - min]++;
for (int i = 1; i < range; i++) count[i] += count[i - 1];
int* temp = (int*)malloc(n * sizeof(int));
if (temp == NULL) exit(1);
for (int i = n - 1; i >= 0; i--) {
int pos = arr[i] - min;
temp[--count[pos]] = arr[i];
}
memcpy(arr, temp, n * sizeof(int));
free(count);
free(temp);
}
7. 排序算法复杂度及稳定性分析总结
算法
平均时间复杂度
最坏时间复杂度
空间复杂度
稳定性
插入排序
O(n²)
O(n²)
O(1)
稳定
希尔排序
O(n^1.3)
O(n²)
O(1)
不稳定
选择排序
O(n²)
O(n²)
O(1)
不稳定
堆排序
O(n log n)
O(n log n)
O(1)
不稳定
冒泡排序
O(n²)
O(n²)
O(1)
稳定
快速排序
O(n log n)
O(n²)
O(log n)
不稳定
归并排序
O(n log n)
O(n log n)
O(n)
稳定
计数排序
O(n+k)
O(n+k)
O(k)
稳定
注:希尔排序的时间复杂度与增量序列选择有关;快速排序的最坏情况发生在基准值选择不当时;计数排序的 k 表示数据范围,适用于整数且范围较小的场景。