C++ 面对昂贵的掉期交易,双支点快速排序

C++ 面对昂贵的掉期交易,双支点快速排序,c++,algorithm,sorting,quicksort,C++,Algorithm,Sorting,Quicksort,将此问题移到,因为它对CS来说似乎不够理论化。 TLDR 有人用昂贵的交换元素测试过双枢轴快速排序性能吗?在这种情况下,它的表现应该大大低于标准快速排序 背景故事 受最近“问题”的启发,我决定去实现给定排序的非平凡版本(,带,中位数3轴选择,小块插入排序等) 在一些研究中,我还发现了双枢轴快速排序。一般来说,它声称它至少总是和标准的快速排序一样好,而且经验测试似乎支持它。(这就是它是当前实现的原因。) 然而,似乎没有STL实现在introsort的快速排序阶段使用双枢轴快速排序,这让我想知道为

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


背景故事
受最近“问题”的启发,我决定去实现给定排序的非平凡版本(,带,中位数3轴选择,小块插入排序等)

在一些研究中,我还发现了双枢轴快速排序。一般来说,它声称它至少总是和标准的快速排序一样好,而且经验测试似乎支持它。(这就是它是当前实现的原因。)

然而,似乎没有STL实现在introsort的快速排序阶段使用双枢轴快速排序,这让我想知道为什么。经过更多的研究,我发现。它说,虽然双枢轴快速排序的比较平均减少5%,但它的交换量却显著增加。(大约增加80%)很明显,因为Java只有原语和引用类型,所以交换总是便宜的。(即使如此,它也只对原语使用这种排序,因为它不稳定)

因此,我想看看是否有人已经测试了标准快速排序与双枢轴快速排序,因为交换元素的成本很高,而且数据(可能还有数据源)到处都是,或者我是否必须自己测试


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

我认为这篇论文中的QuickPortyaroslavskiy()不快速有三个原因

  • 很难找到一个好的支点。通常两个枢轴太近或太远
  • 交换太多了。例如,第12行中的交换是部分数组滑动
  • 实现的插入排序不实用。这篇论文的Knuth算法可能是为了教学而写的。我不喜欢局部数组滑动
  • QuickPortyaroslavskiy()的一个优点是从分区中排除了2个枢轴


    我设计了一种算法来加快快速排序。因为,交换是一种冗余方法,当N较大时,应在各种元素中选择一个轴

    如果您的目标是减少掉期数量,那么您应该回到排序指针。大概是这样的:

    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);
    }
    
    void排序(向量和数据){
    //首先获取一个指针数组。
    向量温度;
    温度储备(数据大小());
    对于(BigClass¤t:数据)温度回推(¤t);
    //排序。
    排序(临时开始(),临时结束(),[](常量BigClass*&a,常量BigClass*&b){
    /*有些lambda通过指针指向的对象来比较指针*/
    });
    //移动对象。
    矢量结果;
    result.reserve(data.size());
    对于(BigClass*电流:温度)结果。向后推(*电流);
    //更新参数
    交换(结果、数据);
    }
    

    这可以保证精确地执行
    data.size()
    copy构造。你做得再好不过了。

    事实上,我在论文中对此进行了广泛的研究


    简而言之,答案是否定的。在交换大型元素时,与高端版本的快速排序相比,Dual Pivot的性能并不好。请看图22和图23。

    可能更适合or。@JonathonReinhart好的,我试着把它放在这里一会儿,晚上再搬过来。(我看不到任何方法可以真正移动问题,而不是删除它并打开一个新的,所以我想在这里给它一个机会。)比较元素(例如长字符串,其中许多元素对于大量的前导字符是相同的)是否也很昂贵?双枢轴快速排序的性能取决于如何实现它。我有一个java版本供参考。它仍然有改进的空间。实际上,改进它是微不足道的,因为您可以跳过已经处于排序位置的元素。也没有回答最初的问题。不,这并不是那么简单:当函数返回时,它的内部存储是另一个。它是为结果数组分配的,所有元素都必须复制到结果数组中。你不能只跳过几个元素,因为它们在排序数组中会丢失。有趣的阅读,但我想指出的是,快速排序传统上一直存在(这就是为什么Introsort切换到heapsort而不是mergesort的原因)。是的,在大多数情况下,就地执行效果更好。但还要注意,即使是就地也使用“交换”,即使用3个复制操作。我使用的方法使用2个复制操作(平均)。