3.3.1 递归计算

728 篇文章 1 订阅
349 篇文章 0 订阅

3.3.1 递归计算

 

递归函数最常见的示例是计算一个数的阶乘。如果你不熟悉,这里有一个简单的定义:一个非负数 n 的阶乘,当 n 等于 1 或 0 时,等于1;对于更大的 n,等于 n-1 的阶乘乘以 n。这个函数的实现,基本上有两种方式。在 C# 中,可以使用 for 循环,数字在 2 到 n 之间进行迭代,用第次迭代的数乘以临时变量:

 

int Factorial(int n) {

  intres = 1;

 for(int i = 2; i <= n; i++)

   res = res * i;

 return res;

}

 

这是一个正确的实现,但不容易看出函数所对应的数学定义。函数的第二种实现方式使用递归,在 C# 中定义方法,或在 F# 中定义函数,以递归方式调用自身。这两个实现惊人的相似,可以在清单 3.12 中看到并列排放的两个定义。

 

清单 3.12 阶乘的递归实现,用C# 和 F#

C#

F#

int Factorial(int n) {  [1]

  if (n <= 1)

    return 1;      [2]

  else

    return n * Factorial(n - 1);  [3]

}

let rec factorial(n) =  [1]

  if (n <= 1) then

    1             [2]

  else

    n * factorial(n - 1)  [3]

 

递归函数或方法的声明[1]。在 F# 中,必须显式声明函数是递归的,用 let rec 绑定,代替普通的 let。

模式匹配包含两种情况。第一种情况,终止递归,并立即返回 1 [2];第二种情况,执行递归调用 factorial 函数或 Factorial 方法。

C# 版本的代码非常简单;F# 版本也相当清晰,只是必须使用 rec 关键字,显式声明函数是递归的。这个关键字说明 let 绑定是递归的,这样,就可以引用函数声明内部值的名字(factorial)。

一般情况下,每个递归计算都应有至少两个分支:一个分支用于执行递归调用的计算,另一个分支用于终止计算,在清单 3.12 中可以看到两个分支。通常,递归计算执行几次递归调用,直到终止条件出现(这里,是计算 1 的阶乘),返回某个常量的值,或使用非递归代码计算结果。如果终止条件不正确,代码可能永远循环下去,或最终由于堆栈溢出异常而崩溃。

递归对于函数编程来说是绝对的核心,因此,函数语言已经开发出一些方法和优化机制,避免了即使深度递归调用,也不会出现堆栈溢出的问题。这些以及更高级的主题将在第十章讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值