在递归函数中,一系列返回如何组合回单个结果?

时间:2014-01-08 02:51:48

标签: scala recursion

我试图了解这个递归函数中发生了什么。它反转了一个String,但我不太明白这些单独的返回调用最后是如何组合成一个字符串的。

def reverse(string: String): String = {
    if (string.length() == 0)
      return string
    return reverse(string.substring(1)) + string.charAt(0)
  }

我已经通过添加print语句分析了这个功能,虽然我有点理解它是如何工作的(从概念上讲),我不明白,嗯...... 它是如何的。< / p>

例如,我知道每个递归循环都会将事物推入堆栈。

所以,我希望reverse("hello")成为一堆

o
l
l
e
h

但它必须比那更复杂,因为递归调用是return reverse(string.substring(1)) + string.charAt(0)。实际上是堆栈

o, 
l, o
l, lo
e, llo
H, ello  

如何将其变成我们期望的单个字符串?

3 个答案:

答案 0 :(得分:6)

堆栈包含所有局部变量,以及递归出现的表达式中的任何临时结果(尽管那些被推送到堆栈上,即使没有递归,因为JVM是一个堆栈机器),当然,这一点代码执行应该在返回时恢复。

在这种情况下,递归调用是整个表达式(也就是说,在它出现的表达式上reverse之前没有计算任何内容)。所以除了代码指针之外唯一的东西是string。在最深层次的递归中,堆栈将如下所示:

level    string
5        (empty string)
4        o
3        lo
2        llo
1        ello
0        hello

因此,当对级别5的调用返回时,级别4将完成计算reverse所属的表达式reverse(string.substring(1)) + string.charAt(0)reverse(string.substring(1))的值为空字符串,string.charAt(0)的值为o(因为第4级string的值为o)。结果是o,返回。

在第3级,它将第4级(o)的返回值与string.charAt(0)的{​​{1}}连接,其string等于lo,即l,结果为ol

在第2级,它将oll连接,并提供oll

第1级将olle连接,并返回olle

等级0,最后,将olleh连接,并将olleh返回给其来电者。

最后一点,当进行调用时,推入堆栈的内容是代码和参数的返回点。所以helloreverse的参数,由reverse的调用者推送到堆栈上。

答案 1 :(得分:6)

使用substitution model解决问题:

reverse("hello") =
(reverse("ello") + 'h') =
((reverse("llo") + 'e') + 'h') =
(((reverse("lo") + 'l') + 'e') + 'h') =
((((reverse("o") + 'l') + 'l') + 'e') + 'h') =
(((((reverse("") + 'o') + 'l') + 'l') + 'e') + 'h') =
((((("" + 'o') + 'l') + 'l') + 'e') + 'h') =
(((("o" + 'l') + 'l') + 'e') + 'h') =
((("ol" + 'l') + 'e') + 'h') =
(("oll" + 'e') + 'h') =
("olle" + 'h') =
"olleh"

答案 2 :(得分:0)

有关如何改进代码的一些提示:

  1. 不要在函数中使用return,因为函数自动返回上次评估行的结果
  2. String是Char的列表,您可以替换string.substring(1)=&gt; string.tai和string.charAt(0)=&gt; string.head
  3. 如果你调用不可变的方法,比如长度,大小等,你可以省略括号string.length()=== string.length
  4. 单行功能的最后一个版本:

    def reverse(s:String):String = if(s.size == 0)s else reverse(s.tail)+ s.head