递归入门必看——写递归的三种方法
递归——可以认为是函数自己调用自己的一个过程
先看一道最简单的递归题——求和 1+2+3…+n=?
显然这个用循环很容易实现(从1加到n)
#include<iostream>
using namespace std;
int main() {
int n, sum = 0;
cin >> n;
for (int i = 1; i <= n; i++)
sum = sum + i;
cout << sum;
return 0;
}
下面用3种递归的方法实现对上述问题的求解
在这之前,再将上述问题简化一下,输出1~n。
在写一个递归函数之前,先要明确它的功能。
就这题来说,递归对i能做的操作,对i+1,i-1同样能做。
下面我要写一个递归函数 func(int i) 功能是显示 i;
#include<iostream>
using namespace std;
int n;//由于递归函数和主函数都要用n,将n定义为全局变量
void func(int i) { //显示i,即这个函数也可以显示i+1,i-1
if (i <= n) {
cout << i << " ";
fun(i + 1);
}
}
int main() {
cin >> n;
func(1);
return 0;
}
在fun(int i)中调用fun(i+1),即显示比他大1的数,使得这个函数逐项递归下去
且这个递归是从小到大实现的。因此我要显示1~n,再主函数中应该从fun(1)开始调用递归。
这里要注意的是,一定要有终止条件 if (i <= n),否则将会一直显示下去。
下面给出这个输入n=3时这个函数递归调用示意图:
尤为要注意的是,每一层传递的参数在内存中不是同一个空间
那在这里变一下,如果我再主函数中调用的不是func(1),而是func(n),这个递归程序该怎么改?我们很容易的想到改为以下代码:
#include<iostream>
using namespace std;
int n;//由于递归函数和主函数都要用n,将n定义为全局变量
void func(int i) { //显示i,即这个函数也可以显示i+1,i-1
if (i >= 1) {
cout << i << " ";//显示功能的实现
fun(i - 1); //递归的实现
}
}
int main() {
cin >> n;
func(n);
return 0;
}
但是发现实现的是倒序输出3 2 1,为什么呢,在此给出递归调用示意图
由此我们得到启示,在写一个递归函数时,要考虑先执行这个函数功能,还是先执行递归,即要考虑功能实现与递归调用的顺序
因此,上面的func应改为
void fun(int i) { //显示i,即这个函数也可以显示i+1,i-1
if (i >= 1) {
fun(i - 1); //递归的实现
cout << i << " ";//显示功能的实现
}
}
即,在这个情况下,要先实现后调用的函数的功能,再实现自己的。
总结一下写递归预备步骤:
1.明确递归函数中参数的意义,和函数的功能
2.函数的功能实现与递归调用的次序
明白了上述微小的差异,现给出第一种实现方法:
p.s.一般我们还是习惯从1~n来实现。(上述第一种调用)
法一 全局函数法(没有返回值)
这里的函数作用是将 i 加到 sum 上
先加上 i 再调用递归,实现1+2+…+n
#include<iostream>
using namespace std;
int n;//由于递归函数和主函数都要用n,sum,将n定义为全局变量
int sum = 0;
void fun(int i) {
if (i <=n) {
sum += i;
fun(i + 1);
}
}
int main() {
cin >> n;
fun(1);
cout << sum;
return 0;
}
注意:如果递归函数没有返回值的话,一定要有一个全局变量
法2 返回值法
这里不仅要明确func(int i)的功能,还要明确func(i)与func(i-1)的关系
函数功能:func(i)求从1到 i 的和
func(i-1)求从1到 i -1 的和
func(i)=i+func(i-1)
参数范围1<=i<=n
这里是向左边界递归故递归跳出条件为i>=1
由于函数的功能是求从1到 i 的和,求1到n的和,故调用func(n)
#include<iostream>
using namespace std;
int n;
int func(int i) { //函数功能:求从1到i的和 func(i-1)求从1到i-1的和
if(i>=1)
return func(i - 1) + i;
return 0;
}
int main() {
cin >> n;
cout << func(n);
return 0;
}
在这里为了更好的理解其内部机制,改为
若改变函数功能:func(i)是求从 i 到 n 的和(这个时候要向右边界递归了)
func(i+1)是求从 i +1到 n 的和
func(i)=i+func(i+1)
参数范围1<=i<=n
跳出条件为i<=n
由于函数的功能是求从1到 i 的和,求1到n的和,故调用func(1)
#include<iostream>
using namespace std;
int n;
//法2:返回值法
int fun(int i) {//函数是求 从i到n的和 fun(i+1)
if(i<=n)
return func(i + 1) + i;
return 0;
}
int main() {
cin >> n;
cout << fun(1);
return 0;
}
法3 带参数直接传递法
int func(int i,int s) 函数中s代表从1到 i-1的和
即每次下一个函数的参数s为 i+s 直到 i 为n,即s中加了n后跳出递归
函数的功能就是把左边的参数加到右边的参数上。
不断调用 func(i+1,i+s)
1->1+s
2->2+s
3->3+s
4->跳出 return s
#include<iostream>
using namespace std;
int n;
int func(int i,int s) { //s代表 1 到 i-1的和
if (i <= n)
return func(i + 1, i + s);//本质是调用,要求的结果在参数中
return s;
}
int main() {
cin >> n;
cout << func(1,0);
return 0;
}
下面变为s代表i+1到n的和
即每次下一个函数的参数s为 i+s 直到 i 为1,即s中加了1后跳出递归
函数的功能就是把左边的参数加到右边的参数上。
不断调用 func(i-1,i+s)
3->3+s
2->2+s
1->1+s
0->跳出 return s
但此法相当于从后往前加
#include<iostream>
using namespace std;
int n;
int func(int i,int s) { //s代表 i+1 到 n的和
if (i >= 1)
return func(i - 1, i + s);//本质是调用,要求的结果在参数中
return s;
}
int main() {
cin >> n;
cout << func(n,0);
return 0;
}
写递归函数总结:
1.明确递归函数中参数的意义,和函数的功能(功能不同调用的机制不同)
2.函数的功能实现与递归调用的次序
3.可以通过画递归过程图帮助理解。
p.s.第三种方法不太常见,主要掌握前两种。