数据结构与算法之美(递归)
一、什么是递归?
说白了 就是自己调用自己 大家应该看过那个 盒子套盒子视频把
常用的 有 dfs啦 还有二叉树(链表形式)遍历
满足递归的条件:
- 一个问题的解可以分解为几个子问题的解,这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样(越来越简单)
- 存在递归终止条件(换句话说 就是出口)
模板:
void recursion(参数0) {
if (终止条件) {
return;
}
recursion(参数1);
}
二、为什么使用递归?递归的优缺点?
- 1.优点:代码的表达力很强,写起来简洁。
- 2.缺点:空间复杂度高、有堆栈溢出风险、存在重复计算、过多的函数调用会耗时较多等问题。
三、什么样的问题可以用递归解决呢?
1,阶乘
//递归法就n的阶乘
public class MainClass {
public static void main(String args[]) {
for (int counter = 0; counter <= 10; counter++){
System.out.printf("%d! = %d\n", counter,
factorial(counter));
}
}
public static long factorial(long number) {
if (number <= 1)
return 1;
else
return number * factorial(number - 1);
}
}
2,斐波那契数列
我们再来看另一道经典的递归题,就是斐波那契数列,数列的前几项如下所示
[1,1,2,3,5,8,13……]
递归的两个条件,一个是终止条件,我们找到了。还一个是调用自己,我们知道斐波那契数列当前的值是前两个值的和,也就是
fibonacci(n) =fibonacci(n - 1) + fibonacci(n - 2)
//1,1,2,3,5,8,13……
public int fibonacci(int n) {
if (n == 1 || n == 2)
return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
3,汉诺塔
相信大家都看过这个吧
汉诺塔的原理这里再简单提一下,就是有3根柱子A,B,C。A柱子上由上至下依次由小至大排列的圆盘。把A柱子上的圆盘借B柱子全部移动到C柱子上,并且移动的过程始终是小的圆盘在上,大的在下。我们还是用递归的方式来解这道题。
#include <bits/stdc++.h>
using namespace std;
void Move(int n, char A, char B, char C)
{
if (n == 1)
{
//圆盘只有一个时,只需将其从A塔移到C塔
cout << "把" << n << " 从" << A << " 移动到" << C << endl;
}
else
{
Move(n - 1, A, C, B);//递归,把A塔上编号1~n-1的圆盘移到B上,以C为辅助塔
cout << "把" << n << " 从" << A << " 移动到" << C << endl;//把A塔上编号为n的圆盘移到C上
Move(n - 1, B, A, C);//递归,把B塔上编号1~n-1的圆盘移到C上,以A为辅助塔
}
}
void Hanoi(int n)
{
if (n <= 0)
return;
Move(n, 'A', 'B', 'C');
}
int main()
{
Hanoi(3);
return 0;
}
四、如何实现递归?
到这里再说 怎么实现 相信大家都看了上面的递归代码了 也明白的差不多了
总的一句 :
写出递推公式,找到终止条件
五、递归常见问题及解决方案
- 警惕堆栈溢出:可以声明一个全局变量来控制递归的深度,从而避免堆栈溢出。
解决方法:
可以通过在代码中限制递归调用的最大深度的方式来解决这个问题 - 警惕重复计算:通过某种数据结构来保存已经求解过的值,从而避免重复计算。
解决方法:
为了避免重复计算,我们可以通过一个数据结构(比如散列表)来保存已经求解过的f(k)。当递归调用到f(k)时,先看下是否已经求解过了。如果是,则直接从散列表中取值返回,不需要重复计算,这样就能避免刚讲的问题了。
六、怎么将递归代码改写为非递归代码?
这个很简单 将递归代码改成循环(也就是迭代)即可 具体怎么写
还是用斐波拉契来说
递归代码:
int fib(int n){
if(n>1) return fib(n-1) + fib(n-2);
else return n; // n = 0, 1时给出recursion终止条件
}
迭代:
int fib(int n){
int i, temp0, temp1, temp2;
if(n<=1) return n;
temp1 = 0;
temp2 = 1;
for(i = 2; i <= n; i++){
temp0 = temp1 + temp2;
temp2 = temp1;
temp1 = temp0;
}
return temp0;
}