递归和迭代算法深入分析
原文链接:https://blog.csdn.net/liujian20150808/article/details/49717427
递归的定义:
程序调用自身的编程技巧称为递归( recursion)。
迭代的定义:
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
接下来我们从一道题来引入这两种算法的比较:
题目描述: QAQ在一个楼梯上,QAQ现在位于第0阶,无聊的QAQ发现,以他腿的长度,每次可以上1阶,2阶,3阶,而这个台阶一共有N阶,那么QAQ走到第N阶共有多少种走法?
TimeLimit: 1000ms MemoryLimit:65536KB
多组测试数据,每组数据一行,包含一个数字N。(1 <= N <= 30)
对于每组数据:
输出到达第N阶共有多少种走法?
解题思路:可以从1开始列举,直到找出规律,原理是加法原理
算法描述:如果用n表示台阶的级数,a n表示某人走到第n级台阶时,所有可能不同的走法,容易得到:
① 当 n=1时,显然只要1种跨法,即a 1=1.
② 当 n=2时,可以一步一级跨,也可以一步跨二级上楼,因此,共有2种不同的
跨法,即a 2=2.
③ 当 n=3时,可以一步一级跨,也可以一步三级跨,还可以第一步跨一级,第二步跨二级或第一步跨二级,第二步跨一级上楼,因此,共有4种不同的跨法,即a 3=4.
④ 当 n=4时,分三种情况分别讨论跨法:
如果第一步跨一级台阶,那么还剩下三级台阶,由③可知有a3 =4(种)跨法.
如果第一步跨二级台阶,那么还剩下二级台阶,由②可知有a2 =2(种)跨法.
如果第一步跨三级台阶,那么还剩下一级台阶,由①可知有a1 =1(种)跨法.
根据加法原理,有a 4= a1 +a2 +a3 =1+2+4=7
类推 ,有
a5= a2 +a3+a4 =2+4+7=13
a6= a3 +a4+a5 =4+7+13=24
a7= a4 +a5+a6=7+13+24=44
a8= a5 +a6 +a7 =13+24+44=81
1.递归算法的源代码:
int digui(int n) { if(n == 1) return 1; if(n == 2) return 2; if(n == 3) return 4; else return digui(n - 1) + digui(n - 2) + digui(n - 3); }
显然,当n值到了34就超时了,这是为什么呢?
下面我们来分析一下该递归程序的运行过程:
当n = 1,2,3的时候,该递归函数都只需要调用1次。
当n = 4的时候,return digui(1) + digui(2) + digui(3) 此时,该递归函数被调用了3次。
当n = 5的时候,return digui(2) + digui(3) + digui(4) 此时,该递归函数被调用了1+1+3=5次。
当n = 6的时候,return digui(3) + digui(4) + digui(5) 此时,该递归函数被调用了1+3+5=9次。
以此类推,有
n7 = n4 + n5 + n6 = 3 + 5 + 9 = 17
n8 = n5 + n6 + n7 = 5 + 9 +17 = 31
n9 = n6 + n7 + n8 = 9+ 17 + 31 = 57
......
这样计算下去到n = 34 的时候,该递归函数累计被调用了235795681次,已经是达到了亿的级别,如果是放在实际工作中,是一件多么可怕的事情,因为使用递归算这种类型的题目,会重复计算很多次,比如说当n = 34的时候,n = 1的时候的取值就被重复计算了53798080-1 = 53798079(可通过递归调用计算次数),重复计算次数都超过了5000万,可想而知算法的效率是多么的低,因此我们可以换一种思路,尽量减少重复计算的次数而提高算法效率,从而引进迭代算法。
2.迭代算法的源代码:
a1 = 1; a2 = 2; a3 = 4; for(i = 4;i <= N;i++) { sum = a1 + a2 + a3; a1 = a2; a2 = a3; a3 = sum; }
而迭代算法到n = 34的时候,耗费的时间也还是忽略不计的
下面分析一下迭代算法的过程:
当n = 1,2,3的时候,跳过for循环,而输出的sum为自身值。
当n = 4的时候,此时for循环次数为1次,计算得sum = 1 + 1 + 1 = 3;
当n = 5的时候,此时for循环次数为2次,第一次计算得sum = 3,然后a2的值赋给a1,a3的值赋给a2,sum的值赋给a3,此时新的a1 = 1,a2 = 1,a3 = 3,然后程序运行到调整部分进行第二次循环,计算得sum = 5,然后跳出for循环输出sum的值为5.
以此类推当n = 6,n = 7......的过程与上述过程类似。
迭代的主要思想就是不断地以旧值来替换新值,从而有效的减少重复计算的次数。
像以上的迭代算法的源代码,当n = 34时,重复计算n = 1,n = 2......的次数均为0,迭代程序就是从n = 4一直计算到n = 34的过程中,一直用旧值替换新值。程序耗费的时间只有for循环耗费的时间。与N的大小有关,呈线性O(n)阶,而且是系数为1的线性阶,for循环的执行次数为n-4.
综上所述,当处理小的循环问题或者是阶乘等问题时,递归算法是一种效率非常低的算法,在找得到更好的算法的情况下,最好不要使用递归算法。