Scala 如何将函数插入排序代码更改为尾部递归

Scala 如何将函数插入排序代码更改为尾部递归,scala,recursion,tail-recursion,insertion-sort,Scala,Recursion,Tail Recursion,Insertion Sort,最近我用函数式编程风格实现了insert_排序算法,它变得更加简洁和声明性。问题是如何将其更改为尾部递归,如果列表的大小增加到10000,代码将抛出异常 def InsertSort(xs: List[Int]): List[Int] = xs match { case Nil => Nil case x::rest => def insert (x: Int, sorted_xs:List[Int]) :List[Int] = sorted_xs m

最近我用函数式编程风格实现了insert_排序算法,它变得更加简洁和声明性。问题是如何将其更改为尾部递归,如果列表的大小增加到10000,代码将抛出异常

def InsertSort(xs: List[Int]): List[Int] = xs match {
    case Nil => Nil
    case x::rest => 
       def insert (x: Int, sorted_xs:List[Int]) :List[Int] = sorted_xs match{
           case Nil => List(x)
           case y::ys => if  (x <= y) x::y::ys else y::insert(x,ys)
       }
       insert(x,InsertSort(rest))
 }
def InsertSort(xs:List[Int]):List[Int]=xs匹配{
案例Nil=>Nil
案例x::rest=>
def insert(x:Int,排序的xs:List[Int]):List[Int]=排序的xs匹配{
案例Nil=>List(x)

案例y::ys=>如果(x刚刚引入了蓄能器:

 @tailrec def InsertSort(xs: List[Int], acc: List[Int] = Nil): List[Int] = 
  if (xs.nonEmpty) {
    val x :: rest = xs
    @tailrec 
    def insert(x: Int, sorted_xs: List[Int], acc: List[Int] = Nil): List[Int] =
      if (sorted_xs.nonEmpty) { 
        val y :: ys = sorted_xs
        if (x <= y) acc ::: x :: y :: ys else insert(x,ys, acc :+ y)
      } else acc ::: List(x)
    InsertSort(rest, insert(x, acc))
  } else acc
最后使用
span
(就像@roterl的回答一样,但是
span
要快一点-它只在找到
>x
之前遍历集合):

def insert(sortedxs:List[Int],x:Int)=if(sortedxs.nonEmpty){
val(更小,更大)=排序的_x.span(xList(1,5,3,6,9,6,7).foldLeft(List[Int]())(插入)
res25:List[Int]=List(1,3,5,6,6,7,9)

要使其尾部递归,应将排序列表作为参数传递,而不是在返回值处构建:

def InsertSort(xs: List[Int]): List[Int] = {
  @tailrec
  def doSort(unsortXs: List[Int], sorted_xs: List[Int]): List[Int] = {
    unsortXs match {
      case Nil => sorted_xs
      case x::rest => 
        val (smaller, larger) = sorted_xs.partition(_ < x)
        doSort(rest, smaller ::: x :: larger)
    }
  }
  doSort(xs, List())  
}
def InsertSort(xs:List[Int]):List[Int]={
@泰勒克
def doSort(unsortXs:List[Int],sortedxs:List[Int]):List[Int]={
反排序匹配{
案例Nil=>sorted_xs
案例x::rest=>
val(较小,较大)=已排序的分区(x
这是我能想到的唯一解决方案。但这段代码几乎不可读。特别是如果你将其与命令式解决方案进行比较。我想知道是否有人知道更优雅的函数式解决方案。或者这是函数式编程的表达能力有其局限性的证据?我添加了foldLeft选项-看起来很漂亮谢谢。你的foldleft版本更具表现力,但也更具抽象性。'partition'只是取代了这里的Insert方法。@dk14的答案更完整。
 def insert(sorted_xs: List[Int], x: Int) = if (sorted_xs.nonEmpty) { 
    val (smaller, larger) = sorted_xs.span(_ < x)
    smaller ::: x :: larger
 } else x :: Nil

 scala> List(1,5,3,6,9,6,7).foldLeft(List[Int]())(insert)
 res25: List[Int] = List(1, 3, 5, 6, 6, 7, 9)
def InsertSort(xs: List[Int]): List[Int] = {
  @tailrec
  def doSort(unsortXs: List[Int], sorted_xs: List[Int]): List[Int] = {
    unsortXs match {
      case Nil => sorted_xs
      case x::rest => 
        val (smaller, larger) = sorted_xs.partition(_ < x)
        doSort(rest, smaller ::: x :: larger)
    }
  }
  doSort(xs, List())  
}