如何在Scala中实现尾递归快速排序
我写了一个递归版本:
def quickSort[T](xs: List[T])(p: (T, T) => Boolean): List[T] = xs match{
case Nil => Nil
case _ =>
val x = xs.head
val (left, right) = xs.tail.partition(p(_, x))
val left_sorted = quickSort(left)(p)
val right_sorted = quickSort(right)(p)
left_sorted ::: (x :: right_sorted)
}
但我不知道如何将其更改为尾递归。谁能给我一个建议吗?
I wrote a recursive version:
def quickSort[T](xs: List[T])(p: (T, T) => Boolean): List[T] = xs match{
case Nil => Nil
case _ =>
val x = xs.head
val (left, right) = xs.tail.partition(p(_, x))
val left_sorted = quickSort(left)(p)
val right_sorted = quickSort(right)(p)
left_sorted ::: (x :: right_sorted)
}
But I don't know how to change it into tail-recurisive. Can anyone give me a suggestion ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
尾递归要求您在每一步中传递已完成的工作和待完成的工作。因此,您只需将要做的工作封装在堆上而不是堆栈上。您可以将列表用作堆栈,这很简单。这是一个实现:
当然,这只是由追溯名链接的蹦床的特殊情况(您不需要向前传递函数)。幸运的是,这个案例很容易手工完成。
Tail recursion requires you to pass work, both completed and work-to-do, forward on each step. So you just have to encapsulate your work-to-do on the heap instead of the stack. You can use a list as a stack, so that's easy enough. Here's an implementation:
This is, of course, just a special case of trampolining as linked to by retronym (where you don't need to pass the function forward). Fortunately, this case is easy enough to do by hand.
我刚刚写了这篇文章,其中包含有关如何将快速排序的经典实现转换为尾递归形式的分步说明:
以尾递归形式重写的快速排序 - Scala 中的示例
我希望您觉得它有趣!
I just wrote this article which contains step by step instructions on how to convert the classic implementation of Quicksort to tail-recursive form:
Quicksort rewritten in tail-recursive form - An example in Scala
I hope you find it interesting!
另一种使用 tailrec、模式匹配和隐式排序的版本:
One more version using tailrec, pattern matching and implicit ordering:
任何递归函数都可以转换为使用堆(而不是堆栈)来跟踪上下文。该过程称为
trampolining
。以下是如何使用 Scalaz 实现它。
当然,您需要一个非常大的结构或一个非常小的堆栈才能解决非尾递归分而治之算法的实际问题,因为您可以处理堆栈深度为 N 的 2^N 个元素。
http://blog.richdougherty.com/2009/04/tail-calls-tailrec-and-trampolines.html
更新
scalaz.Trampoline< /code> 是(更)更通用的结构的特例,
Free
。它的定义为type Trampoline[+A] = Free[Function0, A]
。实际上可以更通用地编写quickSort
,因此它由Free
中使用的类型构造函数参数化。此示例展示了如何完成此操作,以及如何使用相同的代码使用堆栈、堆或并发进行绑定。https://github .com/scalaz/scalaz/blob/scalaz-7/example/src/main/scala/scalaz/example/TrampolineUsage.scala
Any recursive function can be be converted to use the heap, rather than the stack, to track the context. The process is called
trampolining
.Here's how it could be implemented with Scalaz.
Of course, you need either a really big structure or a really small stack to have a practical problem with a non-tail-recursive divide and conquer algorithm, as you can handle 2^N elements with a stack depth of N.
http://blog.richdougherty.com/2009/04/tail-calls-tailrec-and-trampolines.html
UPDATE
scalaz.Trampoline
is a special case of a (much) more general structure,Free
. It's defined astype Trampoline[+A] = Free[Function0, A]
. It's actually possible to writequickSort
more generically, so it is parameterized by the type constructor used inFree
. This example shows how this is done, and how you can then use the same code to bind using the stack, the heap, or in concurrently.https://github.com/scalaz/scalaz/blob/scalaz-seven/example/src/main/scala/scalaz/example/TrampolineUsage.scala