C++ 面对昂贵的掉期交易,双支点快速排序
将此问题移到,因为它对CS来说似乎不够理论化。C++ 面对昂贵的掉期交易,双支点快速排序,c++,algorithm,sorting,quicksort,C++,Algorithm,Sorting,Quicksort,将此问题移到,因为它对CS来说似乎不够理论化。 TLDR 有人用昂贵的交换元素测试过双枢轴快速排序性能吗?在这种情况下,它的表现应该大大低于标准快速排序 背景故事 受最近“问题”的启发,我决定去实现给定排序的非平凡版本(,带,中位数3轴选择,小块插入排序等) 在一些研究中,我还发现了双枢轴快速排序。一般来说,它声称它至少总是和标准的快速排序一样好,而且经验测试似乎支持它。(这就是它是当前实现的原因。) 然而,似乎没有STL实现在introsort的快速排序阶段使用双枢轴快速排序,这让我想知道为
TLDR
有人用昂贵的交换元素测试过双枢轴快速排序性能吗?在这种情况下,它的表现应该大大低于标准快速排序
背景故事
受最近“问题”的启发,我决定去实现给定排序的非平凡版本(,带,中位数3轴选择,小块插入排序等) 在一些研究中,我还发现了双枢轴快速排序。一般来说,它声称它至少总是和标准的快速排序一样好,而且经验测试似乎支持它。(这就是它是当前实现的原因。) 然而,似乎没有STL实现在introsort的快速排序阶段使用双枢轴快速排序,这让我想知道为什么。经过更多的研究,我发现。它说,虽然双枢轴快速排序的比较平均减少5%,但它的交换量却显著增加。(大约增加80%)很明显,因为Java只有原语和引用类型,所以交换总是便宜的。(即使如此,它也只对原语使用这种排序,因为它不稳定) 因此,我想看看是否有人已经测试了标准快速排序与双枢轴快速排序,因为交换元素的成本很高,而且数据(可能还有数据源)到处都是,或者我是否必须自己测试
这个问题专门针对快速排序变体。我认为这篇论文中的QuickPortyaroslavskiy()不快速有三个原因
我设计了一种算法来加快快速排序。因为,交换是一种冗余方法,当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(¤t);
//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个复制操作(平均)。