以下算法的直接剪切和粘貼:歸併排序導致堆棧溢出
def msort[T](less: (T, T) => Boolean)
(xs: List[T]): List[T] = {
def merge(xs: List[T], ys: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys
case (_, Nil) => xs
case (x :: xs1, y :: ys1) =>
if (less(x, y)) x :: merge(xs1, ys)
else y :: merge(xs, ys1)
}
val n = xs.length/2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(less)(ys), msort(less)(zs))
}
}
導致的StackOverflowError 5000成上一長串。
有沒有什麼辦法來優化這個,這樣不會發生?
我曾試圖讓它尾遞歸,然後看到了很多信息,聲稱JVM不適合,並且不總是優化尾遞歸。有什麼指導方針可以成功嗎? – user44242 2010-02-04 20:00:23
JVM沒有,所以Scala編譯器會爲你做。它只在一定的要求下做到:它必須是自遞歸的(即f調用g,g調用f將不起作用),當然它必須是_tail_遞歸(遞歸調用_must_總是最後一件事)代碼路徑),方法必須是「final」或「private」。在這個例子中,因爲'merge'是在'msort'內部定義的,而不是在一個類或對象上定義的,它實際上是私有的。 – 2010-02-04 20:29:53
我認爲這裏值得一提的是,msort本身並不是尾遞歸,而是合併。對於只有編譯器相信的人來說,將@tailrec添加到合併的定義中,您會注意到它已被接受爲尾遞歸函數,就像Daniel概括的那樣。 – 2011-01-29 19:40:54