快速排序与选择排序(Java 与 C++)
我创建了两个项目。一种是 C++ 的,另一种是 Java 的。我对两者进行了快速排序和选择排序的计时试验。奇怪的是我发现了一些非常奇怪的行为。
以下是大小为 10,000 的数组的结果:
SelectionSort Java:80 毫秒
SelectionSort C++:2914 毫秒
QuickSort Java:1 毫秒
QuickSort C++:约 45 秒
现在你可以说我疯了,但我一直被告知 QuickSort 是最快的。这在 Java 中被证明是正确的,但在 C++ 中它完全被关闭了。
所以我的问题是,C++ 处理 QuickSort 的方式是否不同?
我试图保持不同语言之间的函数相同,除了在 C++ 中使用向量与 int 数组之外,它们完全相同。无论如何,我更喜欢使用向量,因为我想在 C++ 中使用排序的实际项目需要向量。
我确信这是一个愚蠢的错误或我正在犯的事情,但请提供一些关于为什么会发生这种情况的见解。
编辑:
我相信我明白问题所在。感谢大家的快速回复。我将修改我的代码以按预期工作。我知道这是一个简单的错误。另外,虽然问的问题很尴尬,但回答很有教育意义。
I created two projects. One in C++ and one in Java. I did time trials for a QuickSort and SelectionSort for both. Oddly enough I found some very strange behavior.
Here were the results for an array of size 10,000:
SelectionSort Java: 80 ms
SelectionSort C++: 2914 ms
QuickSort Java: 1 ms
QuickSort C++: ~45 seconds
Now call me crazy but I've always been taught that QuickSort is the fastest. This proves to be true in Java yet in C++ it completely gets shut down.
So my question is, does C++ handle QuickSort differently?
I tried to keep the functions the same between languages and they are exactly the same with the exception of using a vector in C++ vs an int array. I'd prefer to use a vector anyway because the actual project I want to use the sort for in C++ requires a vector.
I'm sure it's a dumb mistake or something I'm making but please provide some insight as to why this is happening.
EDIT:
I believe I see what the problem is. Thanks everyone for the extremely fast responses. I'll be modifying my code to work as intended. I knew it was a simple mistake. Also, although the question asked is quite embarrassing, the responses are educational.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您的快速排序函数在每次递归调用时按值返回整个向量,即使该函数会就地修改它。可能返回所有这些临时文件然后扔掉它们会损害性能。
只需将函数更改为
void
并删除结尾的 return 并看看它的行为如何。编辑:如果您更习惯 Java,其中几乎所有内容都是垃圾收集引用,请注意,在 C++ 中,按值返回(正如您在返回类型上所做的那样)通常会复制所返回的内容。正如@Johannes Schaub - litb 指出的那样,编译器甚至无法优化返回,因为它没有返回自动(本地)变量。
EDIT2:如果您不这样做作为练习,但您应该使用
std::sort
或std::stable_sort
(后者如果您知道您的数据已经几乎已排序,或者您需要保留重复项的顺序)。例如std::sort(A.begin(), A.end());
Your quicksort function returns your entire vector by value on every recursive call, even though the function modifies it in place. Probably returning all those temporaries and then throwing them away hurts performance.
Just change the function to
void
and remove the ending return and see how it behaves.EDIT: If you're more used to Java where almost everything is garbage collected references, note that in C++ a return by value (as you have on the return type) typically makes a copy of whatever is being returned. And as @Johannes Schaub - litb points out the compiler isn't even able to optimize the return away because it's not returning an automatic (local) variable.
EDIT2: If you aren't doing this as an exercise however you should use either
std::sort
orstd::stable_sort
(the latter if you know your data will already be almost sorted, or you need to preserve the order of duplicates). For examplestd::sort(A.begin(), A.end());
您将在每次递归调用时返回一个完整的向量。这需要花费大量的时间(99.99%的时间都花在了复制上)。
顺便说一句,您可以使用 C++ 中的 STL 排序函数,它保证是快速排序(尽管这会扰乱您的分析,因为您没有进行真正的比较)。
编辑:
显然
std::sort
不保证是快速排序,但保证是 O(n*log(n))。 来源You are returning a complete vector on every recursive call. This takes a lot of time (99,99% of the time spent copying).
By the way, you can use the STL sort function in C++, it's guaranteed to be a quicksort (though this will mess up your profiling because you're not doing a true comparison).
EDIT:
Apparently
std::sort
is not guaranteed to be quicksort, but it is guaranteed to be O(n*log(n)). Source您的 C++ 代码还有另一个问题,似乎尚未有人指出。如果我们去掉计时代码,它就会变得非常明显:
您正在对已经排序的数据进行选择排序。在这种情况下,它可能不会产生很大的影响,但仍然有一些帮助。如果您使用插入排序,它几乎会显示为瞬时的。
There's yet another issue with your C++ code that nobody seems to have pointed out yet. If we get rid of the timing code, it becomes pretty obvious though:
You're doing the selection sort on data that's already sorted. Under the circumstances, it probably doesn't make a huge difference, but still helps some. If you used an insertion sort, it would show up as practically instantaneous.
该问题很可能与您的快速排序的实现有关。如果包含标头并使用
std::sort
——这不是快速排序,而是 introsort,这是一种旨在提高最坏情况性能的变体,结果会完全不同:在运行您的实现时的快速排序我得到的输出类似于:
硬件是 Core2-Duo 2GHz,我用
g++ -O3 -o CompareSorts CompareSorts.cpp
进行编译(请注意,-O3
很重要:它告诉 gcc 尽可能地优化)。The issue is most probably related to your implementation of quicksort. If you include the header and use
std::sort
--which is not quicksort, but introsort, a variant that is meant to improve the worse case performance the results are quite different:While running with your implementation of quicksort I am getting outputs similar to:
The hardware is a Core2-Duo 2GHz, and I compiled with
g++ -O3 -o CompareSorts CompareSorts.cpp
(note that the-O3
is important: it tells gcc to optimize as much as it can).你的C++代码失败了。首先,该标准已经提供了快速排序 -
std::sort
。其次,您为静态大小的数组选择了 std::vector 吗?第三,ftime
和其余的不是有效的分析计时器。第三,即使该函数需要引用,您也会不断从快速排序返回值 - 如果您没有正确设置优化标志,这可能会破坏性能。0.7毫秒。
Your C++ code is fail. Firstly, the Standard already provides a quicksort-
std::sort
. Secondly, you picked astd::vector
- for a statically sized array? Thirdly,ftime
and the rest are not valid profiling timers. Thirdly, you keep returning values fromquicksort
, even though the function takes a reference- if you didn't set the optimization flags correctly this could destroy performance.0.7ms.
我同意 Mark B
你还应该确保:
- 单独运行每个测试
- 多次运行每个测试以获得平均值
- 所有测试使用相同的数据
I agree with Mark B
You should also make sure :
- run each test on its own
- run each test several time to get an average
- use the same data for all the tests
您的代码存在一些问题导致此情况。在 Java 版本中,您对收到的数组进行排序,而在 C++ 版本中,您对向量进行排序并返回它的副本(快速排序的每次递归都会生成一个不必要的副本)。
不要忘记编译带有优化的 C++ 版本 (-O3)。
There are some problems with your code causing this. In the Java version, you sort the array you receive while in the C++ version you sort the vector AND return a copy of it (you make an unecessary copy each recursion of the quicksort).
Don't forget to compile the C++ version with optimization (-O3).
马克 B 在这一点上一语中的。
我在我的设备上使用更新后的代码重复了测试,结果如下
vs
Mark B hit the nail on the head in this one.
I repeated the test with the updated code on my rig with the results
vs