简介
一个数字的阶乘是该整数与所有小于或等于它的正整数的乘积。它必须是一个正整数--否则,逻辑会延伸到负无穷大。换句话说--计算阶乘意味着将一个数字与1之间的所有整数相乘。
**0!**等于1,按照惯例,并不遵循标准规则。
阶乘是由我们要计算阶乘的整数来表示的,后面有一个感叹号。
**5!**表示一个 阶乘的 五.
为了计算这个阶乘,我们把这个数字与比它小的每个整数相乘,直到达到1。
5! = 5 * 4 * 3 * 2 * 1
5! = 120
在本教程中,我们将学习如何使用循环和递归,用JavaScript计算一个整数的阶乘。
使用循环计算阶乘
我们可以使用while 循环和for 循环来计算阶乘。我们通常只需要一个用于循环终止的计数器和我们要计算阶乘的数字。
让我们从for 循环开始。
function getFactorialForLoop(n) {
let result = 1;
if (n > 1) {
for (let i = 1; i <= n; i++) {
result = result * i;
}
return result;
}
else {
return "n has to be positive";
}
}
你可能已经注意到,我们是从1开始计数的,而不是从n --尽管阶乘的定义指出我们从n 到1。尽管在数学上,这些语句是等价的。
为了简化,
(n - (n-1))将永远等于1。
这意味着我们在哪个方向上计数并不重要。它可以从1开始向n 增加,也可以从n 开始向1减少。现在已经清楚了,让我们看看这个方法会发生什么。
它接受n ,即我们要计算阶乘的数字。1 的值被分配给一个占位符result 变量,该变量最终将被更新。
为什么分配1而不是0或其他空白?
如果我们给它赋值0--下面所有的乘法都会有一个0。
然后我们开始我们的for 循环,将i 定义为从1 开始的计数器。注意,条件语句是i <= n; ,以便将n 本身也包括在内。
在for 循环中,我们将result 的当前值与我们的索引i 的当前值相乘--反向执行定义中的操作。
最后,我们返回result 的最终值作为方法的输出。让我们在浏览器的控制台测试一下我们的函数,并打印出结果。请务必先在浏览器的控制台中输入阶乘函数。
var inp = window.prompt("Enter a number: ");
inp = parseInt(inp);
alert("The result is: " + getFactorialForLoop(inp));
它将提示用户进行输入。我们将用4 。当你运行警报脚本时,你会看到一个弹出的结果。
24
你可以用计算器来验证这个结果。
4!是4 * 3 * 2 * 1 ,其结果是24。
现在让我们看看如何用while 循环来计算阶乘。下面是我们修改后的函数。
function getFactorialWhileLoop(n){
let result = 1;
while (n > 1) {
result = result * n;
n -= 1;
}
return result;
}
这与for 循环很相似。除了这次我们从n 向1移动--更接近于数学定义。让我们测试一下我们的函数。
var inp = window.prompt("Enter a number: ");
inp = parseInt(inp);
alert("The result is: " + getFactorialWhileLoop(inp));
像以前一样,如果我们输入4 ,我们得到24 。计算的结果是4*3*2*1 ,最后的结果和之前一样。
因果律在本质上是递归的,使用递归是一种更自然的方法,可以多次重复这样的操作。
使用递归计算阶乘
递归函数是一个可以调用自己的函数。一开始听起来可能有点吓人,但忍一忍,你会发现递归函数很容易理解。
一般来说,每个递归函数都有两个主要组成部分:一个基例和一个递归步骤。
基准案例是问题的最小实例--这就是重复的内容。同时也是一个断点,一个将返回一个值并将走出递归的案例。就阶乘函数而言,基例是当我们返回阶乘的最后一个元素时,也就是1。
如果没有基数情况或基数情况不正确,你的递归函数就会无限地运行,导致溢出。
递归步骤--顾名思义--是函数的递归部分,整个问题在这里被转化为更小的东西。如果递归步骤未能将问题缩小,那么再次递归可以无限地运行。
考虑一下阶乘的递归部分。
- 5!是
5 * 4 * 3 * 2 * 1。
但我们也知道,。
4 * 3 * 2 * 1是4!。
换句话说,5!是5 * 4! ,而4!是4 * 3! ,以此类推。
所以我们可以说,
n! = n * (n-1)!。这将是我们的阶乘的递归步骤!
阶乘的递归在达到1时结束。这将是我们的基本情况。如果n 是1 或更少,我们将返回1 ,涵盖零输入。
让我们看一下我们的递归阶乘函数。
function getFactorialRecursively(n){
if (n <= 1){
return 1;
}
else{
return n * getFactorialRecursively(n-1);
}
}
正如你所看到的,if 块体现了我们的基本情况,而else 块涵盖了递归的步骤。
让我们测试一下我们的函数。
var inp = window.prompt("Enter a number: ");
inp = parseInt(inp);
alert("The result is: " + getFactorialRecursively(inp));
这次我们将输入3 ,警报器将打印6 作为结果。
我们得到同样的结果。但是这一次,引擎盖下的东西相当有趣。
你看,当我们输入时,该函数将检查if ,由于3大于1,它将跳到else 块。在这个块中,我们看到return n * getFactorialRecursively(n-1); 。
我们暂时知道
n的当前值,它是3,但getFactorialRecursively(n-1)仍需计算。
然后程序再次调用同一个函数,但这次我们的函数以2作为参数。它检查了if 块,然后跳到else 块,再次遇到最后一行。现在,n 的当前值是2 ,但程序仍然必须计算getFactorialRecursively(n-1) 。
所以它再次调用该函数,但这次if 块,或者说,基类成功地返回了1,并从递归中脱离出来。
按照同样的模式往上走,它返回每个函数的结果,将当前的结果与之前的n ,并返回给之前的函数调用。换句话说,我们的程序首先到达阶乘的底部(也就是1),然后一路向上,同时在每一步上进行乘法。
同时从调用堆栈中逐一删除函数,直到返回n * (n-1) 的最终结果。
这一般是递归函数的工作方式。一些更复杂的问题可能需要更深层次的递归,有一个以上的基例或一个以上的递归步骤。但是现在,这个简单的递归已经足够解决我们的阶乘问题了!
总结
在这篇文章中,我们介绍了如何使用for 和while 循环来计算阶乘。我们还学习了什么是递归,以及如何使用递归计算阶乘。