递归用法总结
递归定义
递归调用:在调用一个函数的过程中,这个函数本身又直接或间接地调用了函数本身。
通俗地说,举个例子。有5个学生在一起,问第5个学生有多少钱,他说比第4个学生多2块,第四个又说比第三个多2块,第三个比第二个多2块,第二个又比第一个多2块。第一个人说自己只有10块。在这个例子中,我们求第5个人有多少钱的时候,可以通过第四个人,第四个通过第三个,一次类推。这就是递归的思想。
上述求学生钱的例子表达式可以用以下表达式:
money(5) = money(4) + 2;
money(4) = money(3) + 2;
money(3) -= money(2) + 2;
money(2) = money(1) +2;
money(1) = 10;
数学公式如下
money(n) = 10; (n=1)
money(n) = money(n-1) + 2; (n>1)
总的来说,递归要有以下两个条件:
- 基线条件:也就是停止条件
2.递归条件:递归关系的表述
递归的几个经典题目
斐波那契数列
斐波那契数列是:0,1,1,2,3,5,8,13,21,34,55,89,144……依次类推下去,你会发现,它后一个数等于前面两个数的和。在这个数列中的数字,就被称为斐波那契数。
仔细观察我们可以知道,从第三项开始,当前项都等于前两项之和。这就是递归的条件。
long fac(long n){
if(n == 1 || n == 0){
return n;
}
if(n < 0)
return -1; //-1代表错误
return fac(n - 1) + fac(n - 2);
}
阶乘问题
递归表达式:n! = n * (n-1)!
long f(int n){
if( n == 1 || n == 0)
return 1;
if(n < 0)
return -1;
return f(n-1) * n;
}
汉诺塔问题
法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
简单概述如下:
有三根杆子X,Y,Z。X杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至Y杆:
- 每次只能移动一个圆盘;
- 大盘不能叠在小盘上面;
实现如下
void hanoi(int n,char from,char tmp,char to){
if (n>0) {
hanoi(n - 1, from, to, tmp);
cout<<"take " + n + " from " + from + " to " + to;
hanoi(n - 1, tmp, from, to);
}
}
倒叙输出一个正整数
说明:给出正整数 n=12345,希望以各位数的逆序形式输出,即输出54321
递归思想:先输出个位数字,然后在输出个位数字前面的数字,知道没有数字
代码实现如下:
void printNum(int n){
cout << n % 10 << " ";
if( n > 10){
printNum(n / 10);
}
}
排序问题
用递归实现:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。
递归思想
假如针对abc的排列,可以分成
-
以a开头,加上bc的排列
-
以b开头,加上ac的排列
-
以c开头,加上ab的排列
void strfac(string s, int k){
//递归出口条件:当交换到最后时就输出整个字符串 if(k == s.length()) { for(int i = 0; i < k; i++){ cout << s[i] << " "; } cout <<endl; } //开始递归的算法 for(int i = k; i < s.length(); i++){ //将k个字符交换 char t = s[k]; s[k] = s[i]; s[i] = t; //而后递归调用k+1个字符 strfac(s,k+1); //回溯后变回原来的字符 { char t = s[k]; s[k] = s[i]; s[i]= t; } }
}
递归求从 m 个球中摸n个球的排列数
int getSum(int m,int n){
//判断n 是否大于m
if(m < n){
cout << "摸得球数不能大于球总数" << endl;
return 0;
}
if( m == n)
return 1;
if(n == 0)
return 0;
return getSum(m-1,n-1) +getSum(m-1,n);
}
求两个子串的最大公共序列长度
int getsublen(string s1,string s2){
if(s1.length() == 0 || s2.length() == 0)
return 0;
if(s1.at(0) == s2.at(0))
return getsublen(s1.substr(1),s2.substr(1)) + 1;
//不相等则子串加一
else
return max(getsublen(s1.substr(1),s2),getsublen(s1,s2.substr(1)));
}
int max(int a,int b){
if(a > b)
return a;
else
return b;
}
作者:醉曦
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】