我最近学到了quicksort
。我读到枢轴选择在整体性能中起着非常重要的作用。
我有一个任务,我应该在不同的输入大小上测试三个枢轴选择的变化 - 随机化,三个中位数和中位数中位数。
我曾经读过,即使在最坏的情况下,中位数版本的中位数也不会在O(n2)中运行。但在我的研究结果中,随机化和三个版本的中位数给出了几乎相似的结果,三个中位数稍好一些,但中位数的中位数表现非常差几个数量级。例如,在输入大小为50000时,随机版本在16547 us
中运行,而中位数的中位数在1139168 us
中运行。
有人可以解释为什么会这样吗? (据我所知,我已经正确实施了枢轴选择算法 - 将数组潜入5组,取每组的中位数,然后再次递归执行此操作,直到得到中位数。)我做错了什么?
编辑:我正在重新检查代码以防万一,但是中位数实现的中位数与其他两个实现一样慢或甚至更慢(如果只是略微)工作是正常的还是保证工作得更快?
Edit2:这是我用来查找中位数中位数的代码,它找到的值返回到快速排序函数以用作枢轴。我确信代码违反了所有良好的编码习惯,请将此归于我的noob-ishness,并尝试超越它。
int getpivot(int arr[], int low, int high) {
int i,j,k,l,val,med[MAX/4],temp[6],pivot,mi,index,temp2;
if(high-low+1<=5) { //returns median if size of array<=5
for(i=1;i<=high;i++) {
val=arr[i];
j=i-1;
while(j>=0 && val<arr[j]) {
arr[j+1]=arr[j];
j--;
}
arr[j+1]=val;
}
return arr[(low+high)/2];
}
mi=0;
// divide array into groups of 5,
//finds median of those groups by insertion sorting
//adds these medians to med array
for(i=low;i+5<=high;) {
index=0;
for(j=i;j<i+5;j++)
temp[index++]=arr[j];
i+=5;
for(k=1;k<5;k++) {
val=temp[k];
l=k-1;
while(l>=0 && temp[l]>val) {
temp[l+1]=temp[l];
l--;
}
temp[l+1]=val;
}
med[mi++]=temp[2];
}
//choose random index as pivot and partition the med array
pivot=rand()%mi;
i=low=0;
j=high=mi-1;
while(i<j) {
while(i<high && med[i]<=med[pivot]) i++;
while(med[j]>med[pivot]) j--;
if(i<j) {
temp2=med[i];
med[i]=med[j];
med[j]=temp2;
}
}
temp2=med[j];
med[j]=med[pivot];
med[pivot]=temp2;
//j is final position of pivot
//see if j is left/right or equal to the position of true median of median
// and recurse accordingly
low/=5;
high/=5;
if(j==(low+high)/2) return med[j];
else if(j<(low+high)/2) return getpivot(med,j+1,high);
else return getpivot(med,low,j-1);
}
答案 0 :(得分:1)
您的观察结果有点正确。
随机和三个支点选择的中位数应该会带来良好的Quicksort效果,而后者显着更好,如R. Sedgewick的recommended。< / p>
如果阵列在每一步被分成相等的一半(即中位数是枢轴),则在最坏的情况下可以使{QAME}成为O(nlogn)
。现在,中位数中位数算法可以找到线性时间的中位数,使得Quicksort O(nlogn)
处于最坏的情况。
然而,中位数中位数的开销非常高,几乎从未在实践中使用过,因为它会导致性能下降得多。因此,不能仅根据时间复杂度来判断算法的速度,还需要考虑常数因素。