目前,我有一个快速排序算法的准系统实现,可以对一些随机生成的数字进行排序。排序是有效的,比合并排序更有效。但是,对于特定的数字集(例如需要反向排序的反转数字),我需要对枢轴进行优化。
int* partition (int* first, int* last);
void quickSort(int* first, int* last) {
if (last - first <= 1) return;
int* pivot = partition(first, last);
quickSort(first, pivot);
quickSort(pivot + 1, last);
}
int* partition (int* first, int* last) {
int pivot = *(last - 1);
int* i = first;
int* j = last - 1;
for (;;) {
while (*i < pivot && i < last) i++;
while (*j >= pivot && j > first) j--;
if (i >= j) break;
swap (*i, *j);
}
swap (*(last - 1), *i);
return i;
}
因此,对于此代码,我要么使用随机数作为分区步骤的轴,要么使用第一个,中间和最后一个元素的中位数作为轴。
我该怎么做?
我是排序算法的新手,我对它们的理解还不完整。
答案 0 :(得分:2)
只需更改以下行:
int pivot = *(last - 1);
…
swap ((last - 1), i);
类似于:
int* pos = (first + rand(last - first));
int pivot = *pos;
…
swap (pos, i);
或
int* pos = mean_of_three((last - 1), (first), ((first + last) / 2));
int pivot = *pos;
…
swap (pos, i);
其中mean_of_three
取3个指针并返回指向均值的指针。
答案 1 :(得分:2)
正如您已经提到的,选择数组的第一个或最后一个元素作为pivot不是最佳实践,并导致算法落入O(n ^ 2)。 枢轴选择算法的最佳选择取决于程序可能遇到的数据。如果数据有可能被排序或接近排序,那么随机数据转换是一个非常好的选择(并且非常容易实现)以避免O(n ^ 2)行为。另一方面,选择中间元素而不是第一元素的费用是最小的,并且提供了对分类数据的非常有效的保护。
然后,如果您确信您的数据不会被排序或接近排序,那么三分区中位数策略似乎是最好的。
int PickPivotUsingMedian(int a[], int first, int last)
{
int mid = (first+ right)/2;
if (a[mid ] < a[first])
swap(&a[first],&a[mid ]);
if (a[last] < a[first])
swap(&a[first],&a[last]);
if (a[last]< a[mid ])
swap(&a[mid ],&a[last]);
swap(&a[mid], &a[last - 1]);//since the largest is already in the right.
return a[last - 1];
}
答案 2 :(得分:1)
在数组范围内选择一个随机索引,并将该元素用作数据透视。