Performance Floyd–Rivest vs.Introselect算法性能

Performance Floyd–Rivest vs.Introselect算法性能,performance,algorithm,selection,time-complexity,space-complexity,Performance,Algorithm,Selection,Time Complexity,Space Complexity,谷歌帮不上我的忙,所以就这么说吧:两种选择算法,FloydRivest算法和Introselect,哪一种性能更好 我假设这是FloydRivest算法,但要100%确定 此外,如果有更好的算法用于此目的,我很高兴听到他们。TLDR;我认为弗洛伊德·里维斯特更好 我最近为一个项目做了一些关于选择算法的研究。以下是每种算法的基本描述: Introselect:使用单个轴执行数据的二分。最初,选择一个简单的支点,例如中间支点、中间支点3等。在最坏的情况下,简单轴通常位于^2,但平均而言。如果递归级别

谷歌帮不上我的忙,所以就这么说吧:两种选择算法,FloydRivest算法和Introselect,哪一种性能更好

我假设这是FloydRivest算法,但要100%确定

此外,如果有更好的算法用于此目的,我很高兴听到他们。

TLDR;我认为弗洛伊德·里维斯特更好

我最近为一个项目做了一些关于选择算法的研究。以下是每种算法的基本描述:

Introselect:使用单个轴执行数据的二分。最初,选择一个简单的支点,例如中间支点、中间支点3等。在最坏的情况下,简单轴通常位于^2,但平均而言。如果递归级别超过某个阈值,我们将退回到中间值。这是更昂贵的计算,但保证在最坏的情况下。 Floyd Rivest:使用两个数据轴执行数据的五进制分区。选择两个支点,使第k个元素位于它们之间,这很可能涉及随机采样数据,并通过递归选择第n个元素上方和下方的两个元素。当分区的大小变得足够小时,我们使用更简单的方法选择枢轴,例如中位数3等 正如你所看到的,两者非常相似。Introselect从简单的支点开始,回到复杂的支点;Floyd-Rivest算法正好相反。主要区别在于introselect使用中间值的中值,而Floyd Rivest使用递归采样技术。所以,我认为一个更好的比较是中位数和Floyd Rivest

哪个更好?根据我的研究,Floyd Rivest的隐藏常数似乎小于中间值的中值。如果我没记错的话,中位数在最坏的情况下需要5n,而Floyd Rivest只需要3.5n。Floyd Rivest还使用五元模式,当数据可以有很多重复项时,这种模式会更好。对于小输入,introselect和Floyd Rivest都简化为相同的算法,因此只要实现相同的算法,就应该获得类似的性能。在我的测试中,Floyd Rivest比我尝试的所有其他选择算法都快20%。不过,我必须承认,我并没有测试正确的introselect实现,它可以返回到中间值的中间值,我只是测试了libstdc++的伪introselect。在最初的Floyd-Rivest论文中,他们自己是中间值方法的共同作者,他们说中间值的中间值几乎不实用,Floyd-Rivest算法可能是最好的实用选择

所以,在我看来,Floyd Rivest的旋转技术比中间带更好。您可以使用Floyd-Rivest的旋转实现introselect,但也可以使用纯Floyd-Rivest算法。我推荐Floyd Rivest作为最佳选择方法


小心!最初的Floyd Rivest论文给出了他们算法的一个示例实现,这是在撰写本文时维基百科上列出的实现。然而,这是一个简化版本。根据我的测试,简化版实际上相当慢!如果您想要快速实现,我认为您需要实现完整的算法。我推荐阅读Krzysztof C.Kiwiel关于Floyd和Rivest选择算法的论文。他很好地描述了如何实现快速Floyd-Rivest选择。

如果您有真实数据,请获取两个实现并测试它们。两者具有相似的大O时间和空间复杂性;但是,根据实现和提供的数据,两种On算法的性能仍然可能有很大的不同。这就是为什么你会发现很少有人提到X是最好的,这要看情况而定。@tucuxi我认为你应该把你的评论扩展成一个答案。@tucuxi你所说的一切我都知道,这就是为什么我要问这个特定的问题,所以我不需要浪费时间来实现这两个问题。另外,我对一个普通/现实世界的情况很感兴趣。我留下了评论,这样我就不需要浪费时间在实现这两个方面——在我的编程语言、硬件和数据上,当你将它用于不同的东西时。我怀疑您是否会发现两个非可怕的实现之间的差异>10%。拿一个已知且经过良好测试的,并使用它。只有当评测显示这是我真正怀疑的瓶颈时才进行优化。我不相信Floyd Rivest会进行五分之一分区,如果有两个枢轴,则ternery才有意义。它说的是五分位数的划分。但我很肯定,他们是在遵循Bentley&McIlroy在1993年的论文《设计排序函数》中的划分算法。在分区期间,您有5个区域和1个轴值。这5个区域1等于轴2小于轴3未知4大于轴5等于轴。分区后,将移动区域1和5
在中间,区域3现在是0个元素。最终结果:ternery分区是的,从技术上讲,最终结果是三元分区。但是你迭代地细化一个五元划分,直到它收敛到三元划分。这个五元划分方案是Floyd-rivest选择算法的最佳计算复杂度,这就是我指出的原因。