快速排序退化为选择排序
当数据是逆序的时候,patition后每次都是1与n-1,快速排序的时间复杂度就退化为选择排序,为n2。
快速排序的优化
- 可以有效防止快速排序性能退化
- 可以节约栈空间
- 但平均时间复杂度不会降低
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#define SWAP(a, b) { \
__typeof(a) __temp = a; \
a = b; \
b = __temp; \
}
#define TEST(arr, n, func, args...) { \
output(arr, n); \
printf("%s = \n", #func); \
func(args); \
output(arr, n); \
}
void quick_sort(int *num, int left, int right) {
if (left > right) { // 相等的时候,可以再只想一次也可以直接返回
return ;
}
int l = left;
int r = right;
int pivot = num[l]; // 选择基准值
while (l < r) {
while (l < r && num[r] > pivot) { // num[y] > z, 不要写成大于等于。如果是一组全相等的数字,加了等于号,相当于每次patition为1 和 n - 1, 效率低,不加等于号效率更稳定
r--;
}
if (l < r) {
num[l++] = num[r]; // 位置r变为待赋值的位置
}
while (l < r && num[l] < pivot) {
l++;
}
if (l < r) {
num[r--] = num[l]; // 位置l变为待赋值的位置
}
}
num[l] = pivot; // 此时 l == r,为num[l] 或者 num[r]赋值均可
quick_sort(num, left, l - 1);
quick_sort(num, l + 1, right);
return;
}
/* 1. 可以有效防止快速排序性能退化
2. 可以节约栈空间
3. 但平均时间复杂度不会降低
*/
void quick_sort_optimized(int *num, int l, int r) {
while (l < r) {
int x = l, y =r, z = num[(l + r) >> 1]; // 选用中间值为基准值
do {
while (x <= y && num[x] < z) x++;
while (x <= y && num[y] > z) y--;
if (x <= y) {
SWAP(num[x], num[y]); // 这里使用宏,与函数不同,不必要传引用
x++, y--;
}
} while(x <= y); // 这里的小于等于可以保证下面的quick_sort_optimized不会跟while循环重复
quick_sort_optimized(num, x, r);
r = y; // 使用while循环代替递归,可以有效节约栈空间
}
return;
}
void randinit(int *arr, int n) {
for (int i = 0; i < n; i++) {
arr[i] = rand() % 100;
}
return;
}
void output(int *num, int n) {
printf("[");
for (int i = 0; i < n; i++) {
printf("%d ", num[i]);
}
printf("]\n");
return;
}
int main() {
srand(time(0));
#define max_n 20
int *arr = (int *)malloc(sizeof(int) * max_n);
randinit(arr, max_n);
TEST(arr, max_n, quick_sort_optimized, arr, 0, max_n - 1);
free(arr);
#undef max_n
return 0;
}