我的快速排序在已经排序的数据上崩溃了

时间:2014-04-03 21:04:27

标签: crash quicksort

我想检查数组中不同数据的性能时间(随机,已排序,按降序排序)。

void Quicksort(int *T, int Lo, int Hi)
{
  if (Lo<Hi){
      int x=T[Lo];
      int i=Lo, j=Hi;
   do
   {
      while (T[i] < x) ++i;
      while (T[j] > x) --j;
      if (i<=j)
      {
         int tmp = T[i];
         T[i] = T[j];
         T[j] = tmp;
         ++i; --j;
      }
   } while(i < j);
   if (Lo < j) Quicksort(T, Lo, j);
   if (Hi > i) Quicksort(T, i, Hi);
  }
}

以下是用于生成和填充测试数组的函数:

int* createArr(int length){
    int* Arr= new int[length];
    return Arr;
    }

void Random(int *A, int length){
        for (int i=0;i<length;i++){ 
        A[i]=rand();
    }
}
void Order(int *A, int length){
        for (int i=0;i<length;i++){ 
        A[i]=i;
    }
}

void Backwards(int *A, int length){
        for (int i=0;i<length;i++){ 
        A[i]=length-i;
    }
}

它适用于随机数,但是当我尝试按升序填充它并进行排序时,它会因堆栈溢出而崩溃。任何人都可以告诉我为什么会这样吗?

1 个答案:

答案 0 :(得分:0)

当您选择[Lo]项作为分区值(数据透视),并且数组已经排序时,您将得到1到(length-1)的分区。这会导致对数组较长部分的下一个(递归)调用只处理一个比前一个级别少的项目。因此,正如@AlexanderM所指出的那样,您将获得与数组长度一样深的递归。如果数组很大,几乎肯定会导致堆栈溢出。

尝试使用尾部重复:检查哪个部分较短并使用强行呼叫对其进行排序,然后使用较长部分继续当前级别。为此,请将第一个if替换为while并替换

if (Lo < j) Quicksort(T, Lo, j);
if (Hi > i) Quicksort(T, i, Hi);

if (j-Lo < Hi-i)
{
    Quicksort(T, Lo, j);
    Lo = i;
}
else
{
    Quicksort(T, i, Hi);
    Hi = j;
}

这不会使程序更快 - 它在仍然排序的数组上仍然需要O(n ^ 2)时间,但是将防止线性堆栈内存使用,使其保持在最差O(log n)。

有关更好表现的进一步指示,请参阅维基百科文章Quicksort支点选择