快速排序与选择排序(Java与C ++)

时间:2011-05-05 17:31:18

标签: java c++ compare quicksort

我创建了两个项目。一个用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的实际项目需要一个向量。

我确定这是一个愚蠢的错误或我正在制作的东西,但请提供一些有关为何发生这种情况的见解。

编辑:

我相信我明白了问题所在。感谢大家的极快响应。我将修改我的代码以按预期工作。我知道这是一个简单的错误。此外,虽然提出的问题非常令人尴尬,但回应是有教育意义的。

8 个答案:

答案 0 :(得分:18)

你的quicksort函数会在每次递归调用时按值返回整个向量,即使函数在适当的位置修改了它。可能会回归所有那些临时工,然后把它们扔掉,伤害表现。

只需将函数更改为void并删除结束返回并查看其行为。

编辑:如果您更习惯于几乎所有内容都是垃圾收集引用的Java,请注意在C ++中,按值返回(就像返回类型一样)通常会复制正在返回的内容。正如@Johannes Schaub - litb指出编译器甚至无法优化返回,因为它没有返回自动(本地)变量。

EDIT2:如果你不是这样做的话,你应该使用std::sortstd::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