上一节介绍了C语言的“递归函数”,给出了求n的程序! 并分析其执行流程。 事实上,每次递归调用都在重复做同样的事情,就是计算nx(n-1)!。 当然,虽然是“同样的事情”,但还是略有不同(每次n的值都不一样),所以称之为“迭代”更为合适。
计算机特别擅长处理重复性和迭代性工作。 这就是我们人类使用计算机的原因之一,因为人类最不擅长也不喜欢重复、迭代的工作。 对于计算机来说,程序员只是通过编程告诉计算机要做什么。
虽然可以通过递归来解决迭代,但是C语言提供的循环语句更符合我们人类的使用习惯,用起来更舒服。 我们先来看看C语言中的while语句。 其语法为:
while(条件表达式){ 语句; }
当到达while语句时,程序将判断“条件表达式”是真还是假。 如果为 false,则将跳过 while 语句块。 如果为 true,则执行 while 语句块中的内容。 当到达语句块末尾时,程序将返回到“条件表达式”再次判断真或假。 好了,既然我们知道了 while 循环语句的用法,那么我们就用它来计算 n 的阶乘吧。 代码可以写成如下:
int factorial(int n) { int result = 1; while (n > 0) { result = result * n; n = n - 1; } return result; }
同样,我们以(3)为例,讲一下它的执行过程。 程序第一次到达while点时,n=3明显大于0,所以=1 x 3,则n=2; 当返回到while点时,n仍然大于0,所以 = 1 x 3 x 2; 那么n=1,回到刚才,n仍然大于0,所以= 1 x 3 x 2 x 1,那么n = 0; 回到while,0不大于0,所以跳过while语句,函数返回= 6。
许多程序员习惯于调用na循环变量,因为它控制循环体是否循环或结束。
C语言中的循环和递归
上一节我们提到“递归和循环是等价的”,这里举个例子。 然而,递归和循环解决问题的思路不同。 用递归解决这个问题依赖于递归关系n!=n·(n-1)!,而用循环解决这个问题更像是对这个公式的展开:n !=n·(n-1)·(n-2 )·…·3·2·1。 如果把公式展开的话理解起来会更直观,所以有时候循环程序比递归程序更容易理解。
整个递归调用过程中,虽然分配和释放了很多变量,但所有变量都只是在初始化时被赋值,任何变量的值都没有改变。 上面的循环程序基于n和这两个变量。 为了达到同一个目的而进行多项任务。
while使用时的注意事项
既然“递归和循环是等价的”,而如果递归函数写得不当,就会造成无限递归,导致程序最终崩溃。 相应的,如果while循环语句写得不当,也会造成死循环。 该计划成员通常称其为“无限循环”。 while语句死循环的原因很简单,就是while的条件表达式不能为假,程序无法跳出while循环。
上面的例子中,正整数n继续减1,最后n肯定等于0。肯定有n>0为假的时候,所以不会造成死循环。 如果你不小心错过了语句n = n-1,程序将永远不会跳出while循环。 然而,与无限递归不同的是,程序通常不会因无限循环而崩溃。 因此,在使用 while 循环语句之前,请确保 while 的条件表达式有机会为 false,除非你故意想要无限循环。
然而,有时无限循环并不是那么明确,例如下面著名的 3x+1 问题:
while (n != 1) { if (n % 2 == 0) { n = n / 2; } else { n = n * 3 + 1; } }
循环体的作用是:如果n是偶数,则将n除以2。如果n是奇数,则将n乘以3并加1。一般循环变量要么增加要么减少,但在本例中n变大并且越小,最终会变成1吗? 你可以尝试一个号码。 例如,一开始n等于7。 每次循环后,n的值为:7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1。最后n确实等于1. 读者可以多尝试几个数字,这仍然成立,但无论尝试多少个数字,都不能取代证明。 世界上还没有人能够证明这一点。
世界上很多难题都是这样的:描述简单到连小学生都能理解,但证明却如此困难。
欢迎在评论区一起讨论、提问。 文章均为手写、原创。 他们每天都用最简单的方式介绍C语言。 如果你喜欢我的文章,就关注吧,你可以看到最新的更新和往期文章。