Ruby:递归和执行顺序

Ruby:递归和执行顺序,ruby,recursion,Ruby,Recursion,下面方法的输出是[6,4,2,0,0,2,4,6] 我理解n-1处的数组=[6,4,2,0,0],第3行添加了数组[4]=0。但我完全搞不懂为什么即使在执行第3行之后,该方法仍然继续执行,而第3行应该返回[6,4,2,0,0]到原始方法调用。更麻烦的是,n重置为n=1,并递增为n=2和n=3…n=3是在方法调用中传递的起始参数值 另外,我在理解各种可能性中的递归时遇到了很大的问题。如果您能回答这个问题并提出“傻瓜递归”的建议,我们将不胜感激 def append(array, n) retu

下面方法的输出是
[6,4,2,0,0,2,4,6]

我理解n-1处的数组=[6,4,2,0,0],第3行添加了数组[4]=0。但我完全搞不懂为什么即使在执行第3行之后,该方法仍然继续执行,而第3行应该返回[6,4,2,0,0]到原始方法调用。更麻烦的是,n重置为n=1,并递增为n=2和n=3…n=3是在方法调用中传递的起始参数值

另外,我在理解各种可能性中的递归时遇到了很大的问题。如果您能回答这个问题并提出“傻瓜递归”的建议,我们将不胜感激

def append(array, n)
  return array if n < 0 #base case, how we end this thing
  array <<  n*2    #Line No. 1 

  append(array, n - 1) #Line No. 2 
  array <<  n*2    #Line No. 3

end
append( [], 3)

#output  [6,4,2,0,0,2,4,6]
def追加(数组,n)
返回数组如果n<0#基本情况,我们如何结束这件事

array该方法被多次调用。谈论“该方法如何继续执行”已经表明您并没有错误地考虑这一点

方法的每次调用都完全独立于其他每次调用,并且每次调用都有一个唯一的
n
副本及其自身的值。该方法被调用四次,这四次调用中的每一次都将两个项推入数组,总共产生八个项


理解正在发生的事情的关键是,每个方法调用将一个数字推送到数组中,然后调用自身,然后将另一个数字推送到数组中。两个“6”实体都是由相同的方法调用推动的,它们包装了所有其他条目,因为递归发生在两个
array之间,方法被多次调用。谈论“该方法如何继续执行”已经表明您并没有错误地考虑这一点

方法的每次调用都完全独立于其他每次调用,并且每次调用都有一个唯一的
n
副本及其自身的值。该方法被调用四次,这四次调用中的每一次都将两个项推入数组,总共产生八个项


理解正在发生的事情的关键是,每个方法调用将一个数字推送到数组中,然后调用自身,然后将另一个数字推送到数组中。两个“6”实体都是由相同的方法调用推动的,它们包装了所有其他条目,因为递归发生在两个
array之间,我认为您认为
return
结束了一切,但事实并非如此

下面是正在发生的事情,一步一步:

append(array = [], n = 3)                 # initial call
  array << 6                              #Line No. 1
  append(array = [6], n = 2)              #Line No. 2
    array << 4                            #Line No. 1
    append(array = [6,4], n = 1)          #Line No. 2
      array << 2                          #Line No. 1
      append(array = [6,4,2], n = 0)      #Line No. 2
        array << 0                        #Line No. 1
        append(array = [6,4,2,0], n = -1) #Line No. 2
          return array                    #base case
          # but `return` doesn't leave the recursion.
          # it only goes up one step in the call stack, like so:
        array << 0                        #Line No. 3 -> array = [6,4,2,0,0]
      array << 2                          #Line No. 3 -> array = [6,4,2,0,0,2]
    array << 4                            #Line No. 3 -> array = [6,4,2,0,0,2,4]
  array << 6                              #Line No. 3 -> array = [6,4,2,0,0,2,4,6]
另一方面,如果删除
第3行
,最后一行将是调用
append
的结果,这实际上将与
基本情况
一致

append([], 3)   # initial call
  array << 6; append([6], 2)
    array << 4; append([6,4], 1)
      array << 2; append([6,4,2], 0)
        array << 0; append([6,4,2,0], -1)
          return array
        array           # result from the call append([6,4,2], 0) (Line No. 2)
      array             # result from the call append([6,4], 1)   (Line No. 2)
    array               # result from the call append([6], 2)     (Line No. 2)
  array                 # result from the call append([], 3)      (Line No. 2)

#output = [6,4,2,0]
append([],3)#初始调用

数组我认为您认为
return
结束一切,但事实并非如此

下面是正在发生的事情,一步一步:

append(array = [], n = 3)                 # initial call
  array << 6                              #Line No. 1
  append(array = [6], n = 2)              #Line No. 2
    array << 4                            #Line No. 1
    append(array = [6,4], n = 1)          #Line No. 2
      array << 2                          #Line No. 1
      append(array = [6,4,2], n = 0)      #Line No. 2
        array << 0                        #Line No. 1
        append(array = [6,4,2,0], n = -1) #Line No. 2
          return array                    #base case
          # but `return` doesn't leave the recursion.
          # it only goes up one step in the call stack, like so:
        array << 0                        #Line No. 3 -> array = [6,4,2,0,0]
      array << 2                          #Line No. 3 -> array = [6,4,2,0,0,2]
    array << 4                            #Line No. 3 -> array = [6,4,2,0,0,2,4]
  array << 6                              #Line No. 3 -> array = [6,4,2,0,0,2,4,6]
另一方面,如果删除
第3行
,最后一行将是调用
append
的结果,这实际上将与
基本情况
一致

append([], 3)   # initial call
  array << 6; append([6], 2)
    array << 4; append([6,4], 1)
      array << 2; append([6,4,2], 0)
        array << 0; append([6,4,2,0], -1)
          return array
        array           # result from the call append([6,4,2], 0) (Line No. 2)
      array             # result from the call append([6,4], 1)   (Line No. 2)
    array               # result from the call append([6], 2)     (Line No. 2)
  array                 # result from the call append([], 3)      (Line No. 2)

#output = [6,4,2,0]
append([],3)#初始调用

数组这里的执行顺序没有什么神秘之处,并且计数器不会递增。为了理解发生了什么,让我们逐行浏览代码。我将使用
append([],2)
使其更快

# you call append([], 2)
return array if n < 0
# n >= 0 so we continue
array <<  n*2
# array is now [4]
append(array, n - 1)
# you call append(array, 1) which will mutate array,
# lets call x what will be appended to it
# array is now [4, x]
array <<  n*2
# array is now [4, x, 4]
# you get [4, x, 4] as a returned value from the append method
# because after the first line there is no return statement,
# so the return value of the last line is returned

# let's now see what x, that is append(array, 1) is
return array if n < 0
# n >= 0 so we continue
array <<  n*2
# array is now [4, 2] because at that time, array is [4]
append(array, n - 1)
# you call append(array, 0) which will mutate array,
# lets call y what will be appended to it
# array is now [4, 2, y]
array <<  n*2
# array is now [4, 2, y, 2]
# this is what you return to the first method invocation
# so we can replace [4, x, 4] with [4, 2, y, 2, 4]

# let's now see what y, that is append(array, 0) is
return array if n < 0
# n >= 0 so we continue
array <<  n*2
# array is now [4, 2, 0] because at that time, array is [4, 2]
append(array, n - 1)
# you call append(array, -1) which will mutate array,
# lets call z what will be appended to it
# array is now [4, 2, 0, z]
array <<  n*2
# array is now [4, 2, 0, z, 0]
# this is what you return to the second method invocation
# so we can replace [4, 2, y, 2, 4] with [4, 2, 0, z, 0, 2, 4]

# now in the last invocation, z is nothing because -1 < 0,
# so nothing is appended to the array
# the first method invocation returns [4, 2, 0, 0, 2, 4]
你会这样称呼它:

array = append(3)
# [6, 4, 2, 0, 0, 2, 4, 6]
这样,您的数组就不会发生变异,您可以更清楚地了解该方法返回的内容

如果你没有发现它更清晰,那么用这种方式想象它

# append(3)
[6,
    # append(2)
    [4,
        # append(1)
        [2, 
            # append(0)
            [0,
                # append(-1)
                []
            , 0].flatten
        , 2].flatten
    , 4].flatten
, 6].flatten

这里的执行顺序没有什么神秘之处,并且您的计数器不会递增。为了理解发生了什么,让我们逐行浏览代码。我将使用
append([],2)
使其更快

# you call append([], 2)
return array if n < 0
# n >= 0 so we continue
array <<  n*2
# array is now [4]
append(array, n - 1)
# you call append(array, 1) which will mutate array,
# lets call x what will be appended to it
# array is now [4, x]
array <<  n*2
# array is now [4, x, 4]
# you get [4, x, 4] as a returned value from the append method
# because after the first line there is no return statement,
# so the return value of the last line is returned

# let's now see what x, that is append(array, 1) is
return array if n < 0
# n >= 0 so we continue
array <<  n*2
# array is now [4, 2] because at that time, array is [4]
append(array, n - 1)
# you call append(array, 0) which will mutate array,
# lets call y what will be appended to it
# array is now [4, 2, y]
array <<  n*2
# array is now [4, 2, y, 2]
# this is what you return to the first method invocation
# so we can replace [4, x, 4] with [4, 2, y, 2, 4]

# let's now see what y, that is append(array, 0) is
return array if n < 0
# n >= 0 so we continue
array <<  n*2
# array is now [4, 2, 0] because at that time, array is [4, 2]
append(array, n - 1)
# you call append(array, -1) which will mutate array,
# lets call z what will be appended to it
# array is now [4, 2, 0, z]
array <<  n*2
# array is now [4, 2, 0, z, 0]
# this is what you return to the second method invocation
# so we can replace [4, 2, y, 2, 4] with [4, 2, 0, z, 0, 2, 4]

# now in the last invocation, z is nothing because -1 < 0,
# so nothing is appended to the array
# the first method invocation returns [4, 2, 0, 0, 2, 4]
你会这样称呼它:

array = append(3)
# [6, 4, 2, 0, 0, 2, 4, 6]
这样,您的数组就不会发生变异,您可以更清楚地了解该方法返回的内容

如果你没有发现它更清晰,那么用这种方式想象它

# append(3)
[6,
    # append(2)
    [4,
        # append(1)
        [2, 
            # append(0)
            [0,
                # append(-1)
                []
            , 0].flatten
        , 2].flatten
    , 4].flatten
, 6].flatten

递归似乎创建了一个必须逐步展开的嵌套…后进先出???@bscottyoung是的,没错。递归似乎创建了一个必须逐步展开的嵌套…后进先出???@bscottyoung是的,确实如此。如果我在第行之后插入“array@bscottyoung如果你在哪行之后插入它,这个可视化会发生什么?@bscottyoung就是这样发生的:,它不会创建递归嵌套,因为这行不会调用它来自的方法。递归嵌套是对append(append([],2),3)之类的调用。如果我在第行之后插入,这个可视化会发生什么。array@bscottyoung如果你在哪行之后插入它?@bscottyoung这是发生的:,它不会创建递归嵌套,因为这行不会调用它来自的方法。递归嵌套将是对append(append([],2),3)之类的调用。现在我对递归的机制有了更好的理解,您如何确定如何以及何时使用它?我理解解析kings rocks的概念,但我确实希望找到一个讨论各种用途的资源。有什么想法吗?现在我对递归的机制有了更好的理解,你如何决定如何以及何时使用它?我理解解析kings rocks的概念,但我确实希望找到一个讨论各种用途的资源。有什么想法吗?