C++快速排序透视优化

C++ QuickSort Pivot Optimization

本文关键字:优化 透视 快速排序 C++      更新时间:2023-10-16

目前,我有一个快速排序算法的准系统实现来对一些随机生成的数字进行排序。排序是有效的,比合并排序更有效。但是,对于特定的数字集(例如需要反向排序的反转数字(,我需要优化枢轴。

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;
}

因此,对于此代码,我要么要使用随机数作为分区步骤的透视,要么使用第一个、中间和最后一个元素的中位数作为枢轴。

我该怎么做?

我是排序算法的新手,我对它们的理解还没有完成。

只需更改以下行:

    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 个指针并返回指向平均值的指针。

正如您已经提到的,选择数组的第一个或最后一个元素作为枢轴不是最佳实践,并且会导致算法落入 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];
}

在数组边界内选择一个随机索引,并将该元素用作透视。