面对昂贵的互换,双枢轴快速排序

时间:2014-08-14 17:38:51

标签: c++ algorithm sorting quicksort

将此问题移至Programmers,因为它对CS来说似乎不够理论。
TLDR
有没有人用昂贵的交换元素测试双枢轴快速排序性能?在这种情况下,它似乎应该大大低于标准的快速排序。


背景故事
灵感来自最近的"问题" here on stack overflow,我决定去实施给定排序的非平凡版本(introsortquicksort 3-way partition,中间数3个轴位选择,小块插入排序等等。

在一些研究中,我也遇到了双枢轴快速排序,which is the current implementation of quicksort in Java standard library。一般来说,它声称它总是至少和标准的快速排序一样好,并且经验测试似乎支持它。 (这是当前实施的原因。)

然而,似乎没有STL实现使用双枢轴快速排序进入内部的快速排序阶段,这让我想知道为什么。经过更多的研究,我找到了this paper。它表示,虽然双枢轴快速排序平均执行的比较减少了5%,但它的交换次数要多得多。 (大约80%以上)显然,由于Java只有原语和引用类型,因此交换总是很便宜。 (即便如此,它仅对原语使用此类,因为它不稳定)

所以我想看看是否有人已经测试了标准的quicksort vs双枢轴快速排序,当交换元素很昂贵并且数字(可能还有源码)存在时,或者我是否必须自己测试。

此问题专门针对快速排序变体。

3 个答案:

答案 0 :(得分:1)

我在论文中对此进行了广泛的研究。 https://arxiv.org/ftp/arxiv/papers/1505/1505.00558.pdf

简短的回答是,不。当交换大型元素时,与高端版本的快速排序相比,Dual Pivot也不会表现出色。看看图22和23。

答案 1 :(得分:0)

我认为本文的QUICKSORTYAROSLAVSKIY()有三个原因并不快。

  1. 很难获得良好的支点。通常2个枢轴太近或太远。
  2. 交换太多了。例如,在第12行中交换是部分数组滑动。
  3. 实施的插入排序不实用。本文的Knuth算法可能会被写入教学。我不喜欢部分阵列滑动。
  4. QUICKSORTYAROSLAVSKIY()的优点是从分区中排除了2个枢轴。

    我设计了一种算法,使quicksort更快。因为,交换是一种冗余方法,并且当N很大时,应该在各种元素中选择一个枢轴。 More..

答案 2 :(得分:0)

如果你的目标是减少掉期数量,你应该回归到排序指针。像这样:

void sort(vector<BigClass> &data) {
    //First get an array of pointers.
    vector<BigClass*> temp;
    temp.reserve(data.size());
    for(BigClass& current : data) temp.push_back(&current);

    //Sort.
    sort(temp.begin(), temp.end(), [](const BigClass* &a, const BigClass* &b){
        /* some lambda to compare the pointers by the objects they point to */
    });

    //Move the objects.
    vector<BigClass> result;
    result.reserve(data.size());
    for(BigClass* current : temp) result.push_back(*current);

    //Update the argument
    swap(result, data);
}

这可以保证精确data.size()复制结构。你不能做得更好。