我最近回答了一个question问题,试图用Scala编写一个快速排序函数,我在某个地方看到过类似下面代码的东西。
def qsort(l: List[Int]): List[Int] = {
l match {
case Nil => Nil
case pivot::tail => qsort(tail.filter(_ < pivot)) ::: pivot :: qsort(tail.filter(_ >= pivot))
}
}
我的回答收到了一些建设性的批评,指出List是快速排序的一个糟糕的集合选择,其次,上面的方法不是尾部递归的。
我试着用尾部递归的方式重写上面的代码,但是没有太多的运气。有可能写一个尾部递归的快速排序吗?或者,如果没有,它怎么能用函数式的风格来完成呢?还有,怎样才能最大限度地提高实现的效率呢?
5条答案
按热度按时间z0qdvdin1#
几年前,我花了一些时间尽可能地优化函数式快速排序,下面是我为vanilla
List[A]
所做的工作:使用自定义的
List
结构可以做得更好。这个自定义结构基本上跟踪了列表的理想(或 * 接近 * 理想)枢轴点。因此,我可以在恒定时间内获得一个更好的枢轴点,只需访问这个特殊的列表属性。实际上,这比选择头部的标准函数方法要好得多。实际上,上面的方法还是很简洁的,它是“半”尾递归的(你不可能在做一个尾递归的快速排序的时候不变得很难看),更重要的是,它首先从尾部开始重建,所以比传统方法产生的中间列表要少得多。
需要注意的是,这并不是Scala中最优雅或最惯用的快速排序方法,它只是碰巧运行得很好。您可能会在编写合并排序时取得更大的成功,在函数语言中实现合并排序通常是一个更快的算法(更不用说更干净了)。
hfyxw5xn2#
我想这取决于你所说的“惯用”是什么意思。quicksort的主要优点是它是一个非常快的原地排序算法。所以,如果你不能原地排序,你就失去了它所有的优点--但是你仍然坚持它的缺点。
下面是我为Rosetta Code编写的一些代码,它仍然不能就地排序,但另一方面,它可以对任何新集合进行排序:
vohkndzv3#
碰巧我最近也尝试过解决同样的问题,我想把经典的算法(即原地排序的算法)转换成尾部递归形式。
如果您仍然感兴趣,您可以在这里看到我推荐的解决方案:
Quicksort rewritten in tail-recursive form - An example in Scala
本文还包含了我将初始实现转换为尾递归形式所遵循的步骤。
rqenqsqc4#
我做了一些实验,试图用纯函数式风格编写Quicksort,下面是我得到的结果(Quicksort.scala):
ars1skjm5#
我的Scala 3解决方案。