快速排序虽好,但是特殊场景下(如数据有序出现)时间复杂度和空间复杂度会双双爆炸至n^2,导致排序时间过长和栈溢出崩溃。因此需要对代码进行优化。
时间复杂度优化:
使用三者取中的方法可以有效降低最坏情况下的时间复杂度。
三者取中的意思,就是将枢轴的值设置为 A[low] 、A[(low + high)/2] 、A[high] 中的中间值。
空间复杂度优化
使用尾递归优化+两者取短,可以将最坏情况下空间复杂度压缩至logn,具体方法是选取分离后两个子列中较短的先递归,将较长的子列利用尾递优化消除掉,减少系统递归栈的消耗。如果只是单独的使用尾递归优化是无法达到空间优化效果的。
下面的代码经过优化,在vs2019上测试通过,可以无需修改程序栈空间大小(一般编译器都默认1M),完成大量数据排序,测试了1000万个整形数据。
#include <iostream>
#include <time.h>
#define MAX 10000000
void swap(int &a, int &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
int partition(int A[], int low, int high)
{
int mid = (low + high) >> 1;
if (A[low] > A[mid]) swap(A[low], A[mid]);
if (A[low] > A[high]) swap(A[low], A[high]);
if (A[mid] > A[high]) swap(A[mid], A[high]);
int pivot = A[mid]; //三者取中,最坏时间复杂度优化
//int pivot = A[low];
while (low < high)
{
while (low < high && A[high] >= pivot) high--;
A[low] = A[high];
while (low < high && A[low] <= pivot) low++;
A[high] = A[low];
}
A[low] = pivot;
return low;
}
void quicksort(int A[], int low, int high)
{
while (low < high)
{
int part = partition(A, low, high);
if (part < (high + low)>>1) //两者取短 + 尾递归优化,最坏空间复杂度优化至logn,避免了栈溢出
{
quicksort(A, low, part - 1);//短的递归
low = part + 1;//长的优化
// quicksort(A, part + 1, high);
}
else
{
quicksort(A, part + 1, high);
high = part - 1;
// quicksort(A, low, part - 1);
}
}
}
int main()
{
srand((unsigned int)time(NULL));
int *A = new int[MAX];
for (int loop = 0; loop < MAX; loop++)
{
//A[loop] = (rand() % MAX) + 1; //随机数
A[loop] = MAX - loop; //逆序数
//A[loop] = loop; //顺序数
}
quicksort(A, 0, MAX - 1);
int i = 0;
while ( i < MAX)
{
std::cout << "-" << A[i];
i += 10000;
}
}