1.分析下列递归函数。
解析:
2.逆序打印字符串。
具体题目:编写一个函数 reverse_string(char * string)(递归实现),将参数字符串中的字符反向排列,不是逆序打印。例如“abcdefg”,逆序后变为“gfedcba”。
解析:
对于字符串“abcdefg”,递归实现的大概原理:把a和g交换,然后把剩下的bcdef看成一个整体,再次进行相同的操作,即把b和f交换,依此类推;但是,当我交换完a和g之后,剩下的字符串abcdef就无法看成一个字符串了(没有'\0'结尾),所以我们将该步骤变为:
把a备份出来;
把g的值赋给a的位置;
把原来g的位置放上'\0';
逆序中间的bcdef;
最后再把a放到原来g的位置;
依据这个思路,一开始,我们可能会写出这样的版本:
void reverse_string(char* arr)
{
int len = strlen(arr);
char tmp = *arr;
*arr = *(arr + len - 1);
*(arr + len - 1) = '\0';
reverse_string(arr + 1);
*(arr + len - 1) = tmp;
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s\n", arr);
return 0;
}
但显然,这个代码是有问题的,一旦进入reverse_string函数就递归,则会形成死递归,没有跳出递归的条件。我们思考,当中间的字符串只剩下1个字符时,就没有必要进行交换了,而中间的字符串还剩2个及以上时,才有必要进行交换,所以我们添加一个判断条件,保证中间的字符串是大于等于2时,才进行递归。
改正版本:
void reverse_string(char* arr)
{
int len = strlen(arr);
char tmp = *arr;
*arr = *(arr + len - 1);
*(arr + len - 1) = '\0';
if (strlen(arr + 1) >= 2)
reverse_string(arr + 1);
*(arr + len - 1) = tmp;
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s\n", arr);
return 0;
}
3.计算一个数的每位之和
写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19。输入:1729,输出:19
int DigiSum(size_t n)
{
if (n <= 9)
return n;
else
return DigiSum(n / 10) + n % 10;
}
int main()
{
size_t num = 0;
scanf("%u", &num);
int ret = DigiSum(num);
printf("%d\n", ret);
return 0;
}
注意:不要想着创建临时变量存储每位之和,非常不方便;不如直接返回函数的计算值。
4.递归实现n的k次方。
double Pow(int n, int k)
{
if (k == 0)
return 1;
else if (k > 0)
return n * Pow(n, k - 1);
else
return 1.0 / Pow(n, -k);
}
int main()
{
int n = 0;
int k = 0;
scanf("%d %d", &n, &k);
double ret = Pow(n, k);
printf("%lf\n", ret);
return 0;
}
这个比较简单,将其分为三种情况,进行讨论即可。
4.经典的斐波那契额数列问题
什么是斐波那契额数列?
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)。
4.1走台阶问题
亚东上课需要走n阶台阶,因为他腿比较长,所以每次可以选择走一阶或者走两阶,那么他一共有多少种走法?
分析:
假设走10级台阶,那么最后一步只有两种情况,要么走1阶,要么走2阶。如果最后一步走1阶,那么前9级台阶又有f(9)种走法;如果最后一步走2阶,那么前8级台阶又有f(8)种走法。而对于前9级(或前8级)台阶的走法,最后一步任然是两种情况,又可以依次类推,这就是典型的斐波那契数列。实现代码如下:
#include<stdio.h>
int choose(int num)
{
if(num==1)
return 1;
else if(num==2)
return 2;
else
return choose(num-1)+choose(num-2);
}
int main()
{
int n=0;
scanf("%d",&n);
int a=choose(n);
printf("%d",a);
return 0;
}
运行结果如下:
注意:走台阶问题用到的斐波那契数列形式为:1、2、3、5、8、13、21、34…,因为当有2级台阶时,已经有2种走法了。
4.2兔子繁衍问题
一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。输入一个数,求出该月总共的兔子数。(第1个月有一对刚出生的兔子)
#include<stdio.h>
int choose(int num)
{
if (num == 1)
return 1;
else if (num == 2)
return 1;
else
return choose(num - 1) + choose(num - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int a = choose(n);
printf("%d", a);
return 0;
}
注意:这里的兔子繁衍问题用到的斐波那契数列形式为:1、1、2、3、5、8、13、21、34…因为当第2个月时,任然只有1对兔子。
4.3汉诺塔问题
经典汉诺塔问题是,将A中的圆圈,全部移动到C上,每次只能移动一个圆圈,并且要保证大圈在下,小圈在上。 (B作为桥梁)
分析:
当只有2个圈时,只需将‘1’放到B上,然后将‘2’放到C上,最后将‘1’放到C上即可;
当有3个圈时,则将上面两个看成一个整体,然后将‘1’放到B上,将‘2’放到C上,最后将‘1’放到C上即可;当然,这时候将‘1’放到C上,就要借助于A了。
在解决汉诺塔问题时,一定要明确三个塔的关系,一个是圈的其实位置,一个是圈的最终位置,剩下一个则是辅助位置。
代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void move(int n, char x, char y)
{
printf("第%d个盘子从%c--->%c\n", n, x, y);
}
void hanoi(int n, char A, char B, char C)
{
if (n == 1)
{
move(n, A, C);//如果只有一个模块,直接从 A 移动到 C
}
else
{
hanoi(n - 1, A, C, B);//将 n-1个模块从 A 移动到 B
move(n, A, C);
hanoi(n - 1, B, A, C); //将 n-1个模块从 B 移动到 C
}
}
int main()
{
int num;///要移动的盘子数
printf("请输入要移动的盘子数:");
scanf("%d", &num);
hanoi(num, 'A', 'B', 'C');
return 0;
}
运行结果如下: