我创建了两个项目。一个用C ++编写,一个用Java编写。我为QuickSort和SelectionSort进行了时间试验。奇怪的是,我发现了一些非常奇怪的行为。
以下是大小为10,000的数组的结果:
SelectionSort Java:80毫秒
SelectionSort C ++:2914 ms
QuickSort Java:1毫秒
QuickSort C ++:约45秒
现在叫我疯了,但我总是被告知QuickSort是最快的。这在Java中证明是正确的,但在C ++中它完全被关闭。
所以我的问题是,C ++是否以不同的方式处理QuickSort?
我试图在语言之间保持相同的功能,除了在C ++和int数组中使用向量之外,它们完全相同。无论如何我更喜欢使用向量,因为我想在C ++中使用sort的实际项目需要一个向量。
我确定这是一个愚蠢的错误或我正在制作的东西,但请提供一些有关为何发生这种情况的见解。
编辑:
我相信我明白了问题所在。感谢大家的极快响应。我将修改我的代码以按预期工作。我知道这是一个简单的错误。此外,虽然提出的问题非常令人尴尬,但回应是有教育意义的。
答案 0 :(得分:18)
你的quicksort函数会在每次递归调用时按值返回整个向量,即使函数在适当的位置修改了它。可能会回归所有那些临时工,然后把它们扔掉,伤害表现。
只需将函数更改为void
并删除结束返回并查看其行为。
编辑:如果您更习惯于几乎所有内容都是垃圾收集引用的Java,请注意在C ++中,按值返回(就像返回类型一样)通常会复制正在返回的内容。正如@Johannes Schaub - litb指出编译器甚至无法优化返回,因为它没有返回自动(本地)变量。
EDIT2:如果你不是这样做的话,你应该使用std::sort
或std::stable_sort
(后者如果你知道你的数据已经几乎已经分类,或者你需要保留重复的顺序)。例如std::sort(A.begin(), A.end());
答案 1 :(得分:3)
您将在每次递归调用时返回完整的向量。这需要花费大量时间(99,99%的时间用于复制)。
顺便说一句,你可以在C ++中使用STL排序函数,它保证是一个快速排序(虽然这会弄乱你的分析,因为你没有做真正的比较)。
显然std::sort
不能保证是快速排序,但保证是O(n * log(n))。 Source
答案 2 :(得分:2)
你的C ++代码还有一个问题,似乎没有人指出过。如果我们摆脱了时间码,那么它变得非常明显:
quicksort(A,0,length - 1);
SelectionSort(A,length);
您正在对已经排序的数据进行选择排序。在这种情况下,它可能没有产生巨大的差异,但仍然有所帮助。如果您使用插入排序,它将显示为几乎是即时的。
答案 3 :(得分:1)
问题很可能与您的快速排序实施有关。如果您包含标题并使用std::sort
- 这不是快速排序,而是使用introsort,这是一种旨在改善较差案例性能的变体,结果会有很大不同:
$ ./CompareSorts
Quick Sort Took: 1
Selection Sort Took: 101
在使用quicksort的实现运行时,我得到的输出类似于:
$ ./CompareSorts
Quick Sort Took: 41
Selection Sort Took: 95
硬件是Core2-Duo 2GHz,我用g++ -O3 -o CompareSorts CompareSorts.cpp
编译(注意-O3
很重要:它告诉gcc尽可能多地优化。)
答案 4 :(得分:1)
您的C ++代码失败。首先,标准已经提供了快速排序 - std::sort
。其次,你为一个静态大小的数组挑选了一个std::vector
?第三,ftime
,其余的不有效的分析定时器。第三,你继续从quicksort
返回值,即使函数需要引用 - 如果你没有正确设置优化标志,这可能会破坏性能。
int main()
{
std::vector<int> A(array_size);
for(int i = 0; i < array_size; i++)
{
A[i] = rand() % array_size;
}
__int64 begin, end, frequency;
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
QueryPerformanceCounter((LARGE_INTEGER*)&begin);
std::sort(std::begin(A), std::end(A));
QueryPerformanceCounter((LARGE_INTEGER*)&end);
std::cout << "Quick Sort Took: " << ((double)(end - begin) / frequency) * 1000 << std::endl;
std::cin.get();
return 0;
}
为0.7ms。
答案 5 :(得分:0)
我同意Mark B
你还应该确保: - 自己运行每个测试 - 多次运行每次测试以获得平均值 - 对所有测试使用相同的数据
答案 6 :(得分:0)
您的代码存在一些问题导致此问题。在Java版本中,您对在C ++版本中接收的数组进行排序,您对向量进行排序并返回它的副本(每次快速排序的递归都会生成一个不必要的副本)。
不要忘记使用优化(-O3)编译C ++版本。
答案 7 :(得分:0)
Mark B在这一个击中头部的钉子。 我用我的装备上的更新代码重复了测试,结果是
Java QS:7ms
Java SS:111ms
VS
C ++ QS:1ms
C ++ SS:72ms