递归幂函数:如果没有初始返回值,为啥会这样?

Posted

技术标签:

【中文标题】递归幂函数:如果没有初始返回值,为啥会这样?【英文标题】:Recursive power function: Why does this work if there's no initial return value?递归幂函数:如果没有初始返回值,为什么会这样? 【发布时间】:2011-12-01 05:12:58 【问题描述】:

因为 power(base, exponent) 没有返回值,除非 exponent 为 0,所以最初,power(base, exponent -1) 不应该返回“未定义”,因此最初是不可乘的吗?所以,我在遵循这段代码的逻辑时遇到了麻烦。为什么/如何工作?

function power(base, exponent) 
  if (exponent == 0)
    return 1;
  else
    return base * power(base, exponent - 1);

【问题讨论】:

嗯,它从 if 中返回两种情况下的值。真的看不出你有什么问题。 power(13, 5) = 13*(13*(13*(13*(13*power(13, 0)))))。最终值仅在最后一次 power() 调用之后 计算。该函数计算 power(13, 0) 是 1,然后是 13*1,然后是 13*(13)... 哦。你应该提交那个。这是有道理的。 【参考方案1】:

看看如果你尝试计算5^3会发生什么:

power(5, 3)  ... this should give us 125, let's see if it does...

function power(base, exponent)     // base = 5, exponent = 3
  if (exponent == 0)                // nope, exponent != 0
    return 1;
  else
    return base * power(base, exponent - 1);  // return 5 * power(5, 2)

...power(5, 2) 是什么? ...

function power(base, exponent)     // base = 5, exponent = 2
  if (exponent == 0)                // nope, exponent != 0
    return 1;
  else
    return base * power(base, exponent - 1);  // return 5 * power(5, 1)

...power(5, 1) 是什么? ...

function power(base, exponent)     // base = 5, exponent = 1
  if (exponent == 0)                // nope, exponent != 0
    return 1;
  else
    return base * power(base, exponent - 1);  // return 5 * power(5, 0)

...power(5, 0) 是什么? ...

function power(base, exponent)     // base = 5, exponent = 0
  if (exponent == 0)                // yup, exponent != 0
    return 1;                       // return 1
  else
    return base * power(base, exponent - 1);

...把它们放在一起,当我们回到堆栈时,以相反的顺序...

power(5, 0) = returns 1
power(5, 1) = 5 * power(5, 0) = 5 * 1 =  returns 5
power(5, 2) = 5 * power(5, 1) = 5 * 5 =  returns 25
power(5, 3) = 5 * power(5, 2) = 5 * 25 =  returns 125

... so, power(5, 3) returns 125, as it should.

【讨论】:

哦。我就是这么想的,但这只是一种预感。这样写出来就更美了。谢谢你。不过,我能问一下是什么导致它往回走吗? 如果在到达0之前没有返回值,那么它必须从0返回到3并且每次都接收返回,对吗?或者是否有返回值加起来到 0,我们可以列出并“遍历”?很抱歉造成混乱,但我真的不知道“步行”是否意味着程序正在运行数字,或者是否意味着人们可以看到它们,因为它们存在。是技术术语还是什么? 啊,我明白了。因为它是未定义的,所以它只是乘以 13*undefined*13(结果为 13*13),然后最后将结果乘以 1,并因为返回而结束程序。所以,我猜,走路意味着精神上的。酷。【参考方案2】:

可以更简洁:

function power(base, exponent) 
  return exponent == 0? 1 : base * power(base, --exponent);

不过iterative solution 更快:

function powerNR(base, exp) 
  var result = 1;
  while(exp--) 
    result *= base;
  
  return result;

【讨论】:

是否:表示其他和?意思是'如果是,返回以下'? 三元运算符为:(test)? <if true return this> : <if false return this>,等价于:if(test)do somethingelsedo something else 迭代函数更快,因为它只有一个函数调用,递归函数有多个调用(对自身)。函数调用相对昂贵,尽可能避免它们。递归函数可以非常简洁,但这不一定是使用它们的好理由。它们通常难以阅读且速度缓慢(但当您想用少量代码完成大量工作时,它们看起来真的很酷)。 太棒了。感谢您及时通知我,RobG。 请注意,这些实现不处理负指数。 OP 给出的例子也不是,所以我不确定这有什么大不了,但对于那些希望同时处理负指数和正指数的人来说,值得注意。【参考方案3】:

我认为这个函数反过来更有意义,就像这样:

const power = (base, exponent) => 
  if (exponent !== 0) 
    return base * power(base, exponent - 1);
   else 
    return 1;
  

if 语句return 链接在一起,直到 else 语句 执行后才能解析。

示例

4^0 = else;
4^0 = 1

4^1 = if * else;
4^1 = 4 * 1;

4^2 = if * if * else;
4^2 = 4 * 4 * 1;
    = 4 * 4;
    = 16

// Another way of conceptualising it:

4^2 = if(if(else));
    = 4(4(1));
    = 16;

记住if/else 语句return 被沿链向上传递给调用它的函数。

有点愚蠢的比喻

假设你想问大卫一个问题但你不想大喊大叫,你可以问你旁边的人,谁可以问你旁边的人,谁可以问你旁边的人,等等,直到这个问题被问到了大卫。

const askDavidAQuestion = peopleInBetweenYouAndDavid => 

if (peopleInBetweenYouAndDavid !== 0) 

  console.log('I will ask him');

  return askDavidAQuestion(peopleInBetweenYouAndDavid - 1);

 else 

  console.log('David says no');




askDavidAQuestion(3);

-> I will ask him
   I will ask him
   I will ask him
   David says no

只有知道大卫的答案后,才能将该信息传递回提出问题的人的链条。

【讨论】:

【参考方案4】:

创建了对该函数的调用堆栈。这个过程一直持续到它满足终止条件/“基本情况”——这里是一个返回值。此时,所有函数都可以返回,原始函数调用返回答案。换句话说,返回的值从堆栈中弹出并用于计算下一步(以相反的顺序)等等,直到堆栈为空。

使用2^2 示例:

power(2, 2); 调用:

function power(2, 2) 
    if (2 === 0) 
        return 1;
     else 
        return 2 * power(2, 1); // Called (waits in line to be solved)
    

这导致:

function power(2, 1) 
    if (1 === 0) 
        return 1;
     else 
        return 2 * power(2, 0); // Called (waits in line to be solved)
    

这导致:

function power(2, 0) 
    if (0 === 0) 
        return 1; // Returned (previous calls to recursive case can now be solved)
     else 
        return 2 * power(2, -1);
    

既然它有一个可以使用的返回值,那么可以说它可以向外返回。

这导致:

function power(2, 1) 
    if (1 === 0) 
        return 1;
     else 
        return 2 * 1; // Returned
    

这导致:

function power(2, 2) 
    if (2 === 0) 
        return 1;
     else 
        return 2 * 2; // Returned
    

最终返回 4,即 2^2。

【讨论】:

【参考方案5】:
function pow(base, exponent) 
    if (exponent === 0) return 1;
    if (exponent > 0) 
        return base * pow(base, exponent - 1)
     else 
        // handle negative exponent
        return 1 / base * pow(base, exponent + 1)
    

【讨论】:

以上是关于递归幂函数:如果没有初始返回值,为啥会这样?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个函数会返回这个值? [复制]

函数参数,返回值,递归函数

PHP 7.1 - 为啥没有关于 void 返回值的警告?

如果函数没有明确使用'ret',为啥没有返回值

为啥 Rust 在 main 函数中没有返回值,以及如何返回值?

当一个函数无返回值时,函数的类型应定义为啥