在之前我们的 Scratch 课程中,曾经讲过一个经典的算法,这就是递归:
和 Vicky 一起学习 Scratch 系列之二十 —— 递归算法
递归是一个很有用的算法,在很多情况下,可以把看似复杂的问题,简洁巧妙的解决,递归也是各种复杂算法的基础,我们看一个小的例子:
求和
接收用户输入的自然数 n,用递归的方式求 1 到 n 的和。
我们先定义一个求和的函数:
int sum(int n) {
if (n == 1) {
return1;
} else {
return n + sum(n - 1);
}
}
然后,在主函数中调用这个求和函数:
#include <stdio.h>
int sum(int n) {
if (n == 1) {
return1;
} else {
return n + sum(n - 1);
}
}
int main() {
int n;
scanf("%d", &n); // 输入 3
printf("%d", sum(n)); // 输出 6
}
输入 3,1+2+3 的结果就是 6。
而这,就是一个递归函数的简单例子。
递归 recursion 在计算机科学中的定义是这样的:
递归(英语:Recursion),又译为递回,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。
Wikipedia
定义说的很清楚,递归就是在函数内部调用函数自身的情况,看看我们刚刚写的代码:
#include <stdio.h>
int sum(int n) {
if (n == 1) {
return1;
} else {
return n + sum(n - 1);
}
}
int main() {
int n;
scanf("%d", &n); // 输入 3
printf("%d", sum(n)); // 输出 6
}
这里面哪一行体现了递归呢?
或许你已经发现了,就是这一句:
return n + sum(n - 1); // 递归的体现
为什么?
因为这条语句位于函数 sum() 之内,而同时它又调用了 sum() 函数本身,这正是递归的具体体现 —— 在函数的内部调用函数自身。
之前我们提到了,递归算法的优势在于可以很便捷的解决一些看似很复杂的问题。
比如,我们之前在 Scratch 的递归课中,使用递归算法很简单的就画出了一棵看似很复杂的树:
Scratch 实现的递归树
但是递归算法并非没有缺点,它的一个明显的问题是,递归算法的的性能比较低,如果比较看重这一点,还是建议使用循环来替代递归。
此外,太深层次的递归不仅慢,受到内存的限制,还有可能发生 栈溢出 stack overflow 的运行错误。
递归虽好,也要有选择的使用。
好啦,同学们,我们的 C 语言到目前为止已经完成了十多次课,现在我们来回顾一下,我们都讲了哪些内容:
到目前为止,关于 C 语言的理论内容我们已经基本完成了,在接下来的几次课中,我们会具体利用 C 语言,讲解一些典型的信息学竞赛试题,把理论融入于实践,可以更加深刻的体会到 C 语言本身的强大和魅力!