一、函数递归
递归是在程序执行过程中,直接或间接地调用函数自身的过程。通常是要把一个复杂的大规模问题转化成一个个小的问题来求解。递归求解问题在在一些时候可以大大减少代码的复杂程度,增加代码的可读性。
值得注意的是:递归的使用要在每进行一次递归后,问题的规模都要变小;同时递归一定要有递归出口(也就是说,当进行递归到一定程度时,无需在进行递归,直接返回,避免无休止的递归下去)。
//输入一个数字,把它的每一位转化成字符型,并打印(1234->1 2 3 4)
void print(int num)
{
if (num < 10)
{
printf("%c ", num + '0');
return;
}
print(num / 10);
printf("%c ", num % 10 + '0');
return;
}
int main()
{
int num = 1234;
print(num);
system("pause");
return;
}
分析:
//编写函数,不创建临时变量,计算字符串长度
int mystrlen(const char* str)
{
if (*str == '\0')
return 0;
return 1 + mystrlen(str + 1);
}
二、递归与迭代
凡是能通过递归实现的程序,通常可以通过循环转换成迭代形式的。
//eg:编写函数,实现n的阶乘
//递归版本
int factorial(int n)
{
if (n <= 1)
return 1;
return n*factorial(n - 1);
}
//非递归版本
int factorial2(int n)
{
int sum = 1;
while (n > 1)
{
sum *= n;
n--;
}
return sum;
}
递归函数确实能大大减少代码的长度,增加代码的可读性,可是这是一个不断创建栈桢和释放栈桢的过程,性能会大大降低。这个时候可以用循环改写函数,用迭代版本会大大提高程序运行的效率。
//求第n个斐波那契数
//递归版本
int fib(int n)
{
if (n <= 2)
return 1;
return fib(n - 1) + fib(n - 2);
}
//非递归版本
int fib2(int n)
{
int pre = 1;
int ppre = 1;
int cur = 1;
while (n > 2)
{
cur = pre + ppre;
ppre = pre;
pre = cur;
n--;
}
return cur;
}
测试一下上述代码递归和非递归版本计算第30个Fib数所花的时间。
int main()
{
//递归时间
int beg = GetTickCount();
for (int i = 100; i > 0; i--)
{
fib(30);
}
int end = GetTickCount();
printf("time1:%d\n", end - beg);
//非递归时间
int beg2 = GetTickCount();
for (int i = 100; i > 0; i--)
{
fib2(30);
}
int end2 = GetTickCount();
printf("time2:%d\n", end2 - beg2);
system("pause");
return;
}
结果显示,迭代版本明显要比递归版本效率高的多。
并且,当输入的数字特别大,或者递归没有出口,就意味着要不停的建立函数栈桢,但是我们的栈空间是有限的,一旦空间不够用了,就会出现栈溢出。
但也不是不能用递归的方式解决问题,若是问题的规模非常大,难以用不同的方法解决,这是递归的间接性就弥补了它所带来的开销问题。