hyx_蓝桥杯C++学习_系列二
一、递归的介绍
1. 概念
递归是函数直接或间接调用自身的过程
2. 两个关键要素
- 终止条件:防止无限递归,类似于循环的终止条件防止死循环
- 递归表达式:递归的主体,将问题拆分为规模更小的子问题,子问题的答案合并成为当前问题的答案
示例:递归计算斐波那契数列
#include<bits/stdc++.h>
using namespace std;int F(int n){if(n<=2) return 1; // 递归的终止条件,当n <= 2时停止递归else return F(n-1) + F(n-2); // 递归表达式部分,当n >= 3时,F(n) = F(n-1) + F(n-2)
}int main(){int n;cin >> n;int result = F(n);cout << result;return 0;
}
斐波那契数列定义:
- 当 0 < n < 3 时,F(1) 和 F(2) 都等于 1
- 当 n >= 3 时,F(n) = F(n-1) + F(n-2)
3. 直接调用 vs 间接调用
直接调用:函数直接调用自己
#include<bits/stdc++.h>
using namespace std;int factorial(int n){if(n == 0 || n == 1) return 1; // 0和1的阶乘都是1else return n * factorial(n-1); // 递归表达式:n * (n-1)!
}int main(){int n;cin >> n;int result = factorial(n);cout << result;return 0;
}
间接调用:多个函数相互调用
#include<bits/stdc++.h>
using namespace std;int B(int n);int A(int n){if(n<0) return 1;else return B(n-1);
}int B(int n){if(n<0) return 1;else return A(n-2);
}int main(){int n;cin >> n;int result_A = A(n);int result_B = B(n);cout << result_A << " " << result_B;return 0;
}
执行过程分析:
| 输入 n | A(n) 结果 | B(n) 结果 | 执行路径 |
|---|---|---|---|
| 0 | 1 | 1 | A(0)→B(-1)→1 / B(0)→A(-2)→1 |
| 1 | 1 | 1 | A(1)→B(0)→A(-2)→1 / B(1)→A(-1)→1 |
| 2 | 1 | 1 | A(2)→B(1)→A(-1)→1 / B(2)→A(0)→B(-1)→1 |
| 3 | 1 | 1 | A(3)→B(2)→A(0)→B(-1)→1 / B(3)→A(1)→B(0)→A(-2)→1 |
| 4 | 1 | 1 | A(4)→B(3)→A(1)→B(0)→A(-2)→1 / B(4)→A(2)→B(1)→A(-1)→1 |
| 5 | 1 | 1 | A(5)→B(4)→A(2)→B(1)→A(-1)→1 / B(5)→A(3)→B(2)→A(0)→B(-1)→1 |
我们可以发现,无论输入任何正整数,A、B函数的返回值都是1。
二、递归与循环的比较
1. 递归的特点:
- 直观、简洁,易于理解和实现
- 适用于问题的规模可以通过递归调用不断减少的情况
- 可以处理复杂的数据结构和算法,如树和图的遍历
- 存在栈溢出风险(栈空间一般只有8MB,递归层数不宜过深,一般不超过1e6层)
2. 循环的特点:
- 直接控制流程,效率较高
- 适用于问题的规模没有明显的缩减,或者需要特定的迭代次数
- 适合处理大部分的动态规划问题
提示:在部分情况下,递归和循环可以相互转化。
示例:最大公约数的两种实现
递归版本:欧几里得算法
int gcd_recursive(int a, int b){if(b == 0) return a;else return gcd_recursive(b, a % b);
}
循环版本
int gcd_iterative(int a, int b) {while (b != 0) {int temp = a % b;a = b;b = temp;}return a;
}
三、递归应用——汉诺塔问题
1. 什么是汉诺塔问题
有三根柱子(A、B、C),其中一根柱子A上有n个大小不同的圆盘,从小到大依次叠放(最大的在底部,最小的在顶部)。
要求:
- 每次只能移动一个圆盘
- 移动过程中,大圆盘不能放在小圆盘上面
- 最终将所有圆盘从柱子A移动到柱子C
- 可以借助柱子B作为辅助
2. 问题分析
对于n个圆盘:
- 将前n-1个圆盘从A移动到B(借助C)
- 将第n个圆盘(最大的)从A移动到C
- 将n-1个圆盘从B移动到C(借助A)
代码实现
#include<bits/stdc++.h>
using namespace std;int step = 0; void hanoi(int n, char from, char to, char aux) {if (n == 1) {step++;cout << "the " << step << "th step: " << from << " -> " << to << " (disc 1)" << endl;return;}hanoi(n - 1, from, aux, to);step++;cout << "the " << step << "th step: " << from << " -> " << to << " (disc " << n << ")" << endl;hanoi(n - 1, aux, to, from);
}int main() {int n;cout << "the number of disc: ";cin >> n;cout << "\n begin to solve...\n" << endl;hanoi(n, 'A', 'C', 'B');cout << "\n finsh to solve! the sum of step: " << step << endl;return 0;
}
运行结果(n=5):
the number of disc: 5begin to solve...the 1th step: A -> C (disc 1)
the 2th step: A -> B (disc 2)
the 3th step: C -> B (disc 1)
the 4th step: A -> C (disc 3)
the 5th step: B -> A (disc 1)
the 6th step: B -> C (disc 2)
the 7th step: A -> C (disc 1)
the 8th step: A -> B (disc 4)
the 9th step: C -> B (disc 1)
the 10th step: C -> A (disc 2)
the 11th step: B -> A (disc 1)
the 12th step: C -> B (disc 3)
the 13th step: A -> C (disc 1)
the 14th step: A -> B (disc 2)
the 15th step: C -> B (disc 1)
the 16th step: A -> C (disc 5)
the 17th step: B -> A (disc 1)
the 18th step: B -> C (disc 2)
the 19th step: A -> C (disc 1)
the 20th step: B -> A (disc 3)
the 21th step: C -> B (disc 1)
the 22th step: C -> A (disc 2)
the 23th step: B -> A (disc 1)
the 24th step: B -> C (disc 4)
the 25th step: A -> C (disc 1)
the 26th step: A -> B (disc 2)
the 27th step: C -> B (disc 1)
the 28th step: A -> C (disc 3)
the 29th step: B -> A (disc 1)
the 30th step: B -> C (disc 2)
the 31th step: A -> C (disc 1)finsh to solve! the sum of step: 31
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/977815.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!