声明:本文档参考c和指针,如有侵权请联系本人删除!
目录
1、什么是递归函数?
递归函数是直接或间接调用自身的函数。
2、什么情况下可以使用递归函数。
(1)存在限制条件,且当到达限制条件时递归便不再继续。
(2)每次递归之后越来越接近限制条件。
3、递归函数举例
3.1 将二进制整数转换为字符
题目:给出一个整数值7788,我们需要转换成'7'、'7'、'8'、'8'字符输出到屏幕。
如果可以使用printf格式化输出,我们可以直接%d输出7788到屏幕上,但是printf又是怎么实现的。
- 采用的编程思想是把这个值反复除以10,并打印各个余数。
#include <stdio.h>
void binary_to_ascii(unsigned int value)
{
unsigned int quotient;
quotient = value/10;
if(quotient != 0)
binary_to_ascii(quotient);
putchar(value%10 + '0');
}
在上述程序中,递归的限制条件是quotient为0,在每次调用递归之前,我们都把quotient除以10,所以每调用一次递归,它的值就越来越接近0。
递归是如何正确地顺序打印这些字符的呢?
(1)每次递归前将参数值除以10
(2)如果quoient不等于0,则调用递归打印quoient各位数字。
(3)打印步骤(1)的余数
注意:递归函数的每次调用都会把上一个函数的变量压入堆栈中,重新产生一批新的变量。
3.2 计算n的阶乘
阶乘的数学描述:n=1*2*3*…n
(1)当计算到n为0时,递归不再继续,满足限制条件
(2)每调用一次递归,n的值越接近0,满足调用递归后不断逼近限制条件。
实现如下:
#include <stdio.h>
unsigned int factorial(unsigned int n)
{
if(n==0)
return 1;
return n*factorial(n-1);
}
3.3 斐波那契数列
斐波那契数列指的是这样一个数列:0、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)*
(1)当计算到n为2时,递归不再继续,满足限制条件
(2)每调用一次递归,n的值越接近2,满足调用递归后不断逼近限制条件。
实现如下:
#include <stdio.h>
unsigned int fibonacci(unsigned int n)
{
if(n<=2)
return 1;
return fibonacci(n-1)+fibonacci(n-2);
}
4、使用递归的缺点,引出迭代
我们知道,调用递归函数时,系统需要将当前的现场压入堆栈中保存起来,调用完成后再恢复现场,所以当调用递归次数很多时将涉及到堆栈的不断开销,降低系统性能。
(1)阶乘使用递归实现时,计算n的阶乘就要调用n-1次自身函数;
(2)斐波那契数列调用次数更是恐怖,每个递归调用都触发另外两个递归调用,而这两个调用的任何一个还将触发两个递归调用,再接下去也是如此。举个例子,在递归计算Fibonacci(10)时,Fibonacci(3)的值被计算了21次,但是,在递归计算Fibonacci(30)时,Fibonacci(3)的值被计算了317811次,可以看出开销是相当恐怖的。
基于此,我们可以寻找一种可以实现同样功能,但开销却小得多的方法,也就是迭代法。
4.1什么是迭代法
迭代法也称辗转法,是一种不断利用变量旧值递推新值的过程
4.2 迭代法计算n的阶乘
迭代法计算n的阶乘的步骤
(1)定义result =1 ;
(2)当n>1时,result =result *n,n自减1;
(3)返回result值
程序如下:
#include <stdio.h>
long factorial(int n)
{
long result=1;
while(n>1)
{
result *= n;
n--;
}
return result;
}
上面程序,不断利用result旧值重新计算生成新值result,直到循环条件不成立。与递归法对比,不管n值多大,堆栈的开销不变,且实现起来也比较简单,而递归法时,n值很大时,堆栈的开销将不得不重视。
4.3 迭代法计算斐波那契数列
伪代码步骤:
(1)定义当前结果result为0,上一次结果previous_result=1,上上次结果为next_older_result;
(2)循环判断n是否大于2,满足则n自减1,并将上一次结果previous_result赋给上上次结果next_older_result,当前结果result赋给上一次结果previous_result,接着计算当前结果result等于上一次结果和上上次结果之和。
(3)返回计算结果result
程序如下:
#include <stdio.h>
long fibonacci(int n)
{
long result;
long previous_result;//前一个值
long next_older_result;//前前值
result=previous_result=1;
while(n>2)
{
n--;
next_older_result=previous_result;
previous_result=result;
result=next_older_result+previous_result;
}
return result;
}
上述迭代法是利用旧值previous_result和result不断更新新值。编程思想是每循环一次,将previous_result的值赋给next_older_result,result的值赋给previous_result,然后计算next_older_result和previous_result之和。
5、使用递归时注意事项
(1)判断是否满足使用递归条件
(2)如果堆栈开销巨大,是否有其他简单方法可替代
(3)如果使用递归能大大简化程序的复杂性,可着重考虑递归