递归函数 - 为什么不是无限循环?

时间:2013-11-15 02:11:29

标签: javascript

所以这显然是一段有效的代码,但如果power参数除了exponent之外的任何内容,我无法弄清楚如何完成对0的第二次调用。

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

来自:http://imgur.com/Sa2BfHJ

4 个答案:

答案 0 :(得分:8)

因为第二次调用将继续使用exponent中较小的数字调用,直到它达到0,然后返回1,并回滚聚合结果...

我认为你必须在递归上做一些阅读:)

以下是一个简单的案例:

power(2,2) 
 power(2,1) 
    power(2,0) 
       return 1 
    return 2*1 = 2 
 return 2*2 = 4 

从此page获取并修改。

试试an animated view of the recursion的这个页面(对我来说不起作用,这是一个旧页面,需要java,我没有在我的机器上安装它......)


修改
这让我感到困扰,我找不到任何简单的例子,所以这里有一个快速的控制台程序,可以帮助你想象它是如何工作的:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SO_Console
{
    class Program
    {
        static void Main(string[] args)
        {
            int base_value = 0;
            int exponent = 0;
            string[] parts = new string[2];
            int result = 0;
            Console.Out.WriteLine("Please enter the Power to calculate in this format: x^y "
            + Environment.NewLine + "(where x is the base (int) and y is the exponent (int)."
            + Environment.NewLine);

            var temp = Console.ReadLine();
            if (!string.IsNullOrWhiteSpace(temp))
            {

                parts = temp.Split('^');
                if (parts.Length != 2)
                InvalidInput();
            }
            else
            InvalidInput();


            if (Int32.TryParse(parts[0], out base_value) && Int32.TryParse(parts[1], out exponent))
            result = Power(base_value, exponent, "");
            else
            InvalidInput();

            Console.Out.WriteLine(Environment.NewLine + "Final result = {0}", result);


            Console.Out.WriteLine(Environment.NewLine + "Hit any key to quit.");
            Console.Read();

        }

        /// <summary>
        /// Recursive call to calculate Power x^y
        /// </summary>
        /// <param name="base_value">The base</param>
        /// <param name="exponent">The exponent</param>
        /// <param name="padding">Padding, for output.</param>
        /// <returns></returns>
        private static int Power(int base_value, int exponent, string padding)
        {
            Console.Out.WriteLine(string.Format("{2}Power called with: {0}^{1}", base_value, exponent, padding));
            Thread.Sleep(750);

            if (exponent == 0)
            {
                Console.Out.WriteLine("{0}{1}Base case reached, returning 1.{0}", Environment.NewLine ,padding);
                return 1;
            }
            else
            {
                var return_value = base_value * Power(base_value, exponent - 1, padding + "  ");
                Console.Out.WriteLine("{0}Going back in the recursion, returning {1}.", padding, return_value);
                Thread.Sleep(750);
                return return_value;
            }
        }

        /// <summary>
        /// Inform user about bad input and quit.
        /// </summary>
        private static void InvalidInput()
        {
            Console.Out.WriteLine("Invalid input.");
            return;
        }
    }
}

您只需粘贴并运行它,结果就会显示出来:

outputsamuple

编辑2:
我写了一篇关于此的文章,详细解释了为什么会发生什么。欢迎您在此处查看:simple power recursion, console application

答案 1 :(得分:2)

递归仅在您拥有edge case时终止。在取幂的情况下,边缘情况是:

  

n 0 = 1

它读作“任何以0为幂的数字都是1”

取幂的一般情况是:

  

n x = n×n x - 1

在像Haskell这样的数学语言中,取幂将定义如下:

n ^ 0 = 1
n ^ x = n * n ^ (x - 1)

有趣的是,如果你给这个函数一个负整数,那么边缘条件永远不会执行,它会遇到一个无限循环,最终终止于堆栈溢出。

然而,因为我们只使用带有整数(0和正整数)的函数,所以你永远不会遇到无限循环。

然而,如果你使用足够大的指数,你仍然会遇到堆栈溢出,因为计算机只有很大的空间来存储中间结果。

在大多数JavaScript浏览器中,您可以计算2 ^ 2 ^ 14。但是,如果您尝试计算2 ^ 2 ^ 15,则会出现堆栈溢出:http://jsfiddle.net/9chrJ/

答案 2 :(得分:1)

观察x n = x×x n-1 和x 0 = 1.这就是代码正确的原因。< / p>

答案 3 :(得分:1)

试试看一个例子。这是2的3的力量

power(2,3) = 2 * (power(2,2) = 2 * (power(2,1) = 2 * (power(2,0) = 1)))

所以:

power(2,3) = 2 * (2 * (2 * 1)))