什么是递归?
递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法。递归的主要思考方式在于:把大事化小。
递归的两个必要条件
(1)存在限制条件,当满足这个限制条件的时候,递归便不再继续。
(2)每次递归调用之后越来越接近这个限制条件.
接下来说几个栗子来说明递归
练习1
接受一个整型值(无符号),把它转换为字符并打印它。
例如输入:1234,输出 1 2 3 4.
#include <stdio.h>
void print(int n)
{
if(n>9)
{
print(n/10);
}
printf("%d ", n%10);
}
int main()
{
int num = 1234;
print(num);
return 0;
}
结果为:
练习2
递归和非递归分别实现求第n个斐波那契数
//斐波那契数为1 1 2 3 5...,前两个数之和是第三个数
#include <stdio.h>
int factorial(int n)//递归
{
if(n <= 1)
return 1;
else
return n* factorial(n-1);
}
int factorial(int n)//非递归
{
int result = 1;
while (n > 1)
{
result *= n ;
n--;
}
return result;
}
int main()
{
int ret = factorial(4);
printf("ret = %d\n",ret);
}
输出 5
这里在递归下,在调试 factorial 函数的时候,如果你的参数比较大,那就会报错:stack overflow(栈溢出) 这样的信息。
原因是系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出。
解决方法就是降递归改为非递归即迭代,这样就会提高效率,减少栈的开销
练习3
递归和非递归分别实现strlen
#include <stdio.h>
#include <assert.h>
int my_strlen(const char *str)//递归
{
if(*str =='\0')
return 0;
else
return 1+my_strlen(1+str);
}
int my_strlen(const char *str)//非递归
{
int count = 0;
assert(str);
while(*str !='\0')
{
str++;
count++;
}
return count;
}
int main()
{
char *p = "abcdef";
int len = my_strlen(p);
printf("len = %d\n",len);
return 0;
}
练习4
//编写一个函数reverse_string(char * string)(递归实现)
实现:将参数字符串中的字符反向排列。
要求:不能使用C函数库中的字符串操作函数。
#include <stdio.h>
#include <assert.h>
int my_strlen(const char *str)//自己构造一个strlen函数
{
int count = 0;
assert(str);
while(*str !='\0')
{
count++;
str++;
}
return count;
}
char *reverse_string(char *str)//递归
{
int len = my_strlen(str);
char tmp;
if(len>0)
{
tmp = str[0];
str[0] = str[len-1];
str[len-1]='\0';
reverse_string(str+1);
str[len-1] = tmp;
}
return str;
}
int main()
{
char p[] = "abcdefg";
printf("%s\n",reverse_string(p));
return 0;
}
输出:
练习5
编写一个函数实现n^k,使用递归实现
#include <stdio.h>
int my_pow(int n,int k)
{
if(k==0)
{
return 1;
}
else if(k==1)
{
return n;
}
else
return n*my_pow(n,k-1);
}
int main()
{
int n = 2;
int k = 4;
printf("%d\n",my_pow(n,k));
return 0;
}
练习6
写一个递归函数DigitSum(n),输入一个非负整数,
返回组成它的数字之和,例如,调用DigitSum(1729),
则应该返回1+7+2+9,它的和是19
#include <stdio.h>
int DigitSum(int n)
{
if(n<10)
return n;
else
return n%10+DigitSum(n/10);
}
int main()
{
int n = 1729;
printf("%d\n",DigitSum(n));
return 0;
}
温馨提示:
1 . 许多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
2 . 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
3 . 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。