为什么这两个版本的快速排序在进行比较的次数上存在巨大差异

Why do these two versions of quicksort give drastic differences in number of comparisons made?

本文关键字:比较 巨大 存在 快速排序 版本 两个 为什么      更新时间:2023-10-16

下面有两种不同的quicksort实现。我已经验证了这两个版本的快速排序都能正确地对我给出的任何数组进行排序。如果您注意到(至少在我看来),当数组大小n大于8时,Version#2与Version#1完全相同。因此,我希望当我给这两个函数一个大于8的相同大小的数组时,它们平均应该进行相同数量的组件比较,但它们没有。

对于n > 8,两个函数都使用sort3()partition()函数。我也在下面列出了这些,向您展示了我如何计算组件比较的数量。

我知道W(n),这些快速排序实现的理论上最坏情况的比较数是(n(n+2)/4)+8。因此,对于阵列大小n = 500W(n) = 62758。对于在大小为n = 500的数组上进行的测试运行,Version#1平均进行大约5000次比较,这是合理的。然而,版本#2平均进行了80000次比较。显然,这不可能是正确的——版本#2比理论上的W(n)进行了更多的比较,而且它与版本#1完全(至少在我看来)相同。

你看到我在版本#2中犯的错误了吗?

版本#1:

void Quicksort_M3(int S[], int low, int hi)
{
if(low < hi)
{
if((low+1) == hi)
{
comparisons++;
if(S[low] > S[hi])
swap(S[low],S[hi]);
}
else
{
Sort3(S,low,hi);
if((low+2)<hi)
{
swap(S[low+1],S[(low+hi)/2]);
int q = partition(S, low+1, hi-1);
Quicksort_M3(S, low, q-1);
Quicksort_M3(S, q+1, hi);
}
}
}
}

版本#2:

void Quicksort_Insert_M3(int S[], int n, int low, int hi)
{
if((hi-low)<=8)
Insertionsort(S,n);
else 
{
if(low < hi)
{
if((low+1) == hi)
{
comparisons++;
if(S[low] > S[hi])
swap(S[low],S[hi]);
}
else
{
Sort3(S,low,hi);
if((low+2)<hi)
{
swap(S[low+1],S[(low+hi)/2]);
int q = partition(S, low+1, hi-1);
Quicksort_Insert_M3(S, n, low, q-1);
Quicksort_Insert_M3(S, n, q+1, hi);
}
}
}
}
}

分区:

int partition(int *S,int l, int u)
{
int x = S[l];
int j = l;
for(int i=l+1; i<=u; i++)
{
comparisons++;
if(S[i] < x)
{   
j++;
swap(S[i],S[j]);
}
}
int p = j;
swap(S[l],S[p]);
return p;
}

第3类:

int Sort3(int list[], int p, int r)
{
int median = (p + r) / 2;
comparisons++;
if(list[p] <= list[median])
{
comparisons++;
if(list[median]>list[r])
{
comparisons++;
if(list[p]<list[r])
{
int temp = list[p];
list[p] = list[r];
list[r] = list[median];
list[median] = temp;
}
else
{
exchange(list,median,r);
}
}
else
;
}
else
{
comparisons++;
if(list[p] > list[r])
{
comparisons++;
if(list[median] < list[r])
{
int temp = list[p];
list[p] = list[median];
list[median] = list[r];
list[r] = temp;
}
else
{
exchange(list,p,r);
}
}
else
{
exchange(list,p,median);
}
}

return list[r];
}

我认为您的错误是,当您进行插入排序时,您仍然使用数组的原始大小。因此,您最终会对整个数组进行插入排序。