针对待排序列中农存在大量重复键值的情况,上一节讲了一种对快排算法的优化,代码如下:
template<typename T>
int __patition(T arr[], int l, int r)
{
swap(arr[l], arr[rand() % (r - l + 1) + l]);
T v = arr[l];
int i = l + 1, j = r;
while(true)
{
while(i <= r && arr[i] < v)
{
i++;
}
while(j >= l + 1 && arr[j] > v)
{
j--;
}
if(i > j)
{
break;
}
swap(arr[i++],arr[j--]);
}
swap(arr[j], arr[l]);
return j;
}
template<typename T>
void __quickSort(T arr[], int l, int r)
{
if(l >= r)
{
return;
}
else
{
int p = __patition(arr, l, r);
__quickSort(arr, l, p - 1);
__quickSort(arr, p + 1, r);
}
}
template<typename T>
void quickSort(T arr[], int n)
{
srand(time(0));
__quickSort(arr, 0, n - 1);
}
实际上还存在一种针对重复键值的经典优化快排算法,称为3路快速排序算法,这种排序算法相比上一节的优化效率更高,3路快排将待排序列分为3部分:<v、==v、>v,则进行递归时,对==v的部分就不用考虑,只需考虑对<v和>v部分进行递归排序,如图所示:
若 i 指向的元素<v,则交换arr[lt+1]和arr[i],然后i++,若 i 指向的元素==v,则直接i++,若 i 指向的元素>v,则交换arr[i]和arr[gt-1],此时不需要维护 i ,只需要将gt--即可,整个过程就是这样的,最后的结果如下图所示:
最后将arr[l]和arr[lt交换]。
接下来递归只针对<v和>v的部分进行递归即可,可以看出,对于含有很多重复键值的序列来说,可以省去对==v部分进行下一层递归操作,这将节省很多时间。
3路快速排序算法的C++实现如下,我们将之前讲的2种快排和3路快排进行时间性能上的比较:
SortTestHelper.h文件(包含辅助函数