C++ 当数组具有重复值时,为什么快速排序算法的持续时间会增加?
我试图使用std::chrono time计算并使用某个范围内随机生成的整数数组[A,B]来测量合并排序和快速排序函数的持续时间,数组的大小从5000到100000个整数不等 我的代码的目标是证明,当快速排序中选择(枢轴)的方法得到改进时,快速排序函数最终处理数组的时间比合并排序少,我选择枢轴的方法是使用随机索引方法来最小化复杂性为(n^2)的概率,然而,在我将在下面描述的某些情况下,快速排序最终比合并排序花费更多的时间,我想知道为什么会发生这种情况 案例1: 数组中的数字范围很小,这增加了数组中存在重复数字的概率 案例2: 当我使用像clion这样的本地IDE时,快速排序函数比合并排序花费的时间要多得多,但是像IDEONE.com这样的在线编译器在两种排序算法中给出了相似的结果(即使生成的整数范围很小) 以下是我在上述情况下得到的结果(第一行数字是合并排序结果,第二行是快速排序结果): 1-clion结果数字范围窄(-100600) 具有广泛数字范围的2-clion结果(INT_MIN,INT_MAX) 数字范围很窄的3-IDEONE结果(-100600) 4-数字范围广泛的表意文字结果(INT_MIN,INT_MAX)C++ 当数组具有重复值时,为什么快速排序算法的持续时间会增加?,c++,performance,time-complexity,quicksort,mergesort,C++,Performance,Time Complexity,Quicksort,Mergesort,我试图使用std::chrono time计算并使用某个范围内随机生成的整数数组[A,B]来测量合并排序和快速排序函数的持续时间,数组的大小从5000到100000个整数不等 我的代码的目标是证明,当快速排序中选择(枢轴)的方法得到改进时,快速排序函数最终处理数组的时间比合并排序少,我选择枢轴的方法是使用随机索引方法来最小化复杂性为(n^2)的概率,然而,在我将在下面描述的某些情况下,快速排序最终比合并排序花费更多的时间,我想知道为什么会发生这种情况 案例1: 数组中的数字范围很小,这增加了数组
#包括
#包括
#包括
使用名称空间std;
mt19937 gen(时钟::稳定时钟::现在().自新纪元以来的时间().计数());
int*generatarray(int大小)
{
int*arr=新的int[size];
均匀分布(最小值、最大值);
对于(int i=0;i 对于(int i=0;i已知,当输入集包含大量重复项时,快速排序的性能较差。解决方案是使用三向分区,如上所述:
重复元素
使用如上所述的分区算法(甚至
如果选择了好的轴心点值,快速排序将表现出较差的性能
包含许多重复元素的输入的性能
当所有的输入元素都相等时,问题很明显:at
每次递归,左分区都是空的(没有输入值小于
右分区只减少了一个
元素(轴心被移除)。因此,算法需要
对相等值数组进行排序的二次时间
为了解决这个问题(有时称为),可以使用替代的线性时间划分例程
将值分为三组:小于
轴,值等于轴,值大于轴。
…价值观
等于轴的已排序,因此只有小于和
大于的分区需要递归排序。在伪代码中,
快速排序算法变为
algorithm quicksort(A, lo, hi) is
if lo < hi then
p := pivot(A, lo, hi)
left, right := partition(A, p, lo, hi) // note: multiple return values
quicksort(A, lo, left - 1)
quicksort(A, right + 1, hi)
输出:
0 1 2 3 4 5 6 7 8 9 11 11 12 13 14 15 16 19 18 19
0 0 0 1 0 1 1 1 1 1 2 3 2 2 2 2 3 3 3 3
0 1 2 3 4 5 6 6 8 8 9 12 11 12 13 14 16 17 18 19
0 0 1 1 1 2 3 3 3 4 4 4 5 6 5 6 7 7 8 8
因此,使用大量重复项的运行现在要快得多
当数组具有重复值时,为什么快速排序算法的持续时间会增加
这只有在使用Lomuto类型的分区方案时才是正确的,其中重复的值会导致拆分变得更糟
如果使用霍尔分区方案,当数组具有重复值时,算法持续时间通常会缩短,因为拆分更接近于完全对半拆分的理想情况,并且改进的拆分可以补偿具有内存缓存的典型系统上的额外交换。如果在代码中交换顺序,会发生什么d首先测量合并排序,然后快速排序?用于编译的编译器选项是什么?编译器是mingw64,交换顺序会得到相同的结果。什么编译器选项?优化已打开?您能详细说明吗?我不知道如何共享我的编译器选项,但我确信我没有更改任何clion编译器选项。是吗这是调试版还是发布版?请注意,wiki文章后来被更正为只针对Lomuto分区方案存在此问题。对于Hoare分区方案,随着重复值数量的增加,拆分更接近理想情况,即完全对半拆分,足以补偿在典型系统上进行的更多交换使用缓存。
pair<int,int> partition(int* arr, int left, int right)
{
int idx = left + (right - left) / 2;
int pivot = arr[idx]; // to be improved to median-of-three
int i = left, j = left, b = right - 1;
while (j <= b) {
auto x = arr[j];
if (x < pivot) {
swap(arr[i], arr[j]);
i++;
j++;
} else if (x > pivot) {
swap(arr[j], arr[b]);
b--;
} else {
j++;
}
}
return { i, j };
}
void quickSort(int* arr, int left, int right)
{
if (left < right)
{
pair<int, int> part = partition(arr, left, right);
quickSort(arr, left, part.first);
quickSort(arr, part.second, right);
}
}
0 1 2 3 4 5 6 7 8 9 11 11 12 13 14 15 16 19 18 19
0 0 0 1 0 1 1 1 1 1 2 3 2 2 2 2 3 3 3 3
0 1 2 3 4 5 6 6 8 8 9 12 11 12 13 14 16 17 18 19
0 0 1 1 1 2 3 3 3 4 4 4 5 6 5 6 7 7 8 8