递归

来源:互联网 发布:js定义空数组长度 编辑:程序博客网 时间:2024/04/28 13:57
 递归做为一种算法在程序设计语言中广泛应用.是指函数/过程/子程序在运行过程序中直接或间接调用自身而产生的重入现像.


递归

递归是一项非常重要的编程技巧,它使函数调用其本身。示例之一就是阶乘的计算。0 的阶乘被明确地定义为 1。n(大于 0 的整数)的阶乘是 1 到 n 之间所有整数的乘积。
使用递归

以下段落是用文字定义的一个阶乘计算函数。

如果数字小于零,则将其拒绝。如果数字不是整数,则将其拒绝。如果数字为零,其阶乘则为一。如果数字大于零,则将其乘以下一个更小数字的阶乘。

若要计算任一个大于零的数字的阶乘,必须至少计算另外一个数字的阶乘。函数在对当前数字执行计算之前,必须先对小于当前数字的相邻数字调用其自身。这就是递归的示例。

递归和迭代(循环)密切相关,即函数可以使用递归或迭代返回相同的结果。通常,某个计算适用于一种技巧或另一种技巧,您只须选择最自然或最理想的方法。

虽然递归的用处很大,但是如果使用不慎,创建的递归函数就可能从不返回结果并且不能到达终点。这种递归导致计算机执行“无限” 循环。下面是一个示例:忽略阶乘计算文字描述中的第一项规则(有关负数的规则),然后计算任意负数的阶乘。这种计算失败的原因是:若要计算 -24 的阶乘,必须计算 -25 的阶乘,要计算 -25 的阶乘,必须先计算 -26 的阶乘,依此类推。显然,这种计算永远得不出结果。

递归可能出现的另一个问题是:递归函数可能用尽所有可用的资源(如系统内存、堆栈空间等等)。每次递归函数调用自身(或调用另一个函数,而另一个函数又调用原来的函数),递归函数就会占用一些资源。当递归函数退出时,就会释放这些资源,但是函数的递归层次过多,就会用尽所有可用的资源。发生这种情况时,就会引发异常。

因此,谨慎设计递归函数是非常重要的。如果怀疑可能出现递归过多(或无限递归)的情况,则设计函数时就应加入计算函数调用其自身的次数的功能,并设置调用次数限制。如果函数调用自身的次数超过阈值,则函数可以自动退出。迭代的最大次数的最佳取值取决于递归函数。

下面又是一个阶乘函数,这一次是用 JScript 代码编写的。还使用了类型批注,使函数只接受整数。如果传递的数字无效(即小于零的数),则 throw 语句就会产生一个错误。否则,使用递归函数计算阶乘。递归函数采用两个参数,一个用作阶乘参数,另一个用作跟踪当前递归层次的计数器。如果计数器没有达到最大递归层次,则返回原始数字的阶乘。

function factorialWork(aNumber : int, recursNumber : int ) : double {
   // recursNumber keeps track of the number of iterations so far.
   if (aNumber == 0) {  // If the number is 0, its factorial is 1.
      return 1.;
   } else {
      if(recursNumber > 100) {
         throw("Too many levels of recursion.");
      } else {  // Otherwise, recurse again.
         return (aNumber * factorialWork(aNumber - 1, recursNumber + 1));
      }
   }
}

function factorial(aNumber : int) : double {
   // Use type annotation to only accept numbers coercible to integers.
   // double is used for the return type to allow very large numbers to be returned.
   if(aNumber < 0) {
      throw("Cannot take the factorial of a negative number.");
   } else {  // Call the recursive function.
      return  factorialWork(aNumber, 0);
   }
}

// Call the factorial function for two values.
print(factorial(5));
print(factorial(80)); 
原创粉丝点击