Với đoạn mã sau:danh Xếp Scala
import scala.util.Random
object Reverser {
// Fails for big list
def reverseList[A](list : List[A]) : List[A] = {
list match {
case Nil => list
case (x :: xs) => reverseList(xs) ::: List(x)
}
}
// Works
def reverseList2[A](list : List[A]) : List[A] = {
def rlRec[A](result : List[A], list : List[A]) : List[A] = {
list match {
case Nil => result
case (x :: xs) => { rlRec(x :: result, xs) }
}
}
rlRec(Nil, list)
}
def main(args : Array[String]) : Unit = {
val random = new Random
val testList = (for (_ <- 1 to 2000000) yield (random.nextInt)).toList
// val testListRev = reverseList(testList) <--- Fails
val testListRev = reverseList2(testList)
println(testList.head)
println(testListRev.last)
}
}
Tại sao phiên bản đầu tiên của hàm thất bại (vì những đóng góp lớn), trong khi biến thể thứ hai hoạt động. Tôi nghi ngờ đó là một cái gì đó liên quan đến đệ quy đuôi, nhưng tôi không chắc chắn lắm. Ai đó có thể vui lòng cho tôi lời giải thích "cho người giả" không?
Tại sao không sử dụng 'val testListRev = testList.reverse'? – Lutz
Câu hỏi này được hỏi một thời gian dài trước đây, nhưng đây là câu trả lời cho câu hỏi đệ quy đuôi của bạn. Có, đó là vì tối ưu đệ quy đuôi. Trong lần thực hiện đầu tiên của bạn, case (x :: xs) => reverseList (xs) ::: List (x), sau khi gọi reverseList đệ quy, chương trình phải thêm List (x) vào nó. Điều này có nghĩa rằng nó không thể được tối ưu thành một vòng lặp, trong ví dụ thứ hai của bạn: case (x :: xs) => {rlRec (x :: result, xs)} rlRec là cuộc gọi cuối cùng, không có gì để làm sau khi nó thoát và đây là lý do tại sao nó không phải tạo một khung Stack mới cho nó. – loteq