迭代与嵌套是面向过程的两个非常有用的算法,在一些java开发中也应用的比较多。今天学习了一些皮毛,将其总结如下。
1线型的递归和迭代:
线型过程结构比较简单,比较容易理解,并且从描述到代码的书写比较容易实现。最常见的是计算阶乘:
1.1、用迭代的想法是,从1开始计算,每次乘上新的i,新计算的结果代替旧的结果:n->n*i;
int n=1; for(int i=1;i<n;i++){ n=n*i; }
1.2、用嵌套的想法是,f(n)=nf(n-1),当n等于1时返回1;于是
private static int factorial(int n){ if(n==1) return 1; else return n*factorial(n-1); }
1.3、迭代的过程比较简单,不想多说,在写程序时,可以写成迭代的尽量使用迭代,嵌套相对而言更消耗计算资源。
这里要简单的说一下迭代的整个计算过程。编写嵌套算法,最重要有两点:程序的出口和程序过程。例如
程序的出口是指,程序最末端程序应该返回的值,例如在1.2中的if(n==1) return 1;就是程序的末端。
有了程序的末端,就要去设计程序的过程,嵌套的过程并不容易书写,很容犯错。比如有这样两个方法,很类似,得出的结果相差却很大:
private static void show1(int i) { // TODO 自动生成的方法存根 if (i < 6) t(i + 1); else System.out.print(i + " "); }
private static void show2(int i) { // TODO 自动生成的方法存根 if (i < 6) t(i + 1)
System.out.print(i + " "); }
同样给i初值是1时,show1打印的是6,show2打印的 是6 5 4 3 2 1。
分析一下这两个程序,show1(1),返回show1(2)。。。最后,当show1(6)时,程序结束,打印6。而show2(1)就不一样了,show2(1)的出口也是6,但是,在执行show1(1)时,程序有一部分(system.out.print(…))没有执行,因为程序进入了下一个嵌套show2(2),称没有执行的语句被暂时挂起。这样每个循环都被挂起一段代码,直到show2(6)时,程序找到出口,开始往回执行嵌套过程。先打印6 之后5 再4 。。。注意打印不是先1 再2 再3 。。。
由此也可见,在嵌套中出口对于程序是很重要的。
嵌套的计算机算法可以理解为,先挂起执行代码直到找到出口,从出口开始执行代码。
还有一个经典的例子是求最大公约数的问题,这里就不多说过程了,将前人的算法留下。数学过程是,(a,b)的最大公约数,与(b,a%b)的最大公约数相等,算法因欧几里德而出名,命名为欧几里德辗转算法。代码这里就不在给出了
当然线型过程都是可以优化的,在这里就不多说了。
如果说线型结构相对而言简单一下,树形结构要复杂很多,也更管用,可以解决许多日常世纪问题。
2、树形递归
树形算法要复杂很多,并且使用嵌套的方式更容易理解。
一个简单的例子是斐波数:
最常用的数学描述f(n)=f(n-1)+f(n-2)。n=2时 1,n=1时 1。
使用迭代或者是递归的方法都很容易实现,这里就不在写详细的实现过程了。简单的把嵌套的树形图画一下:
树形过程还是挺复杂的,上面只是一个最简单的例子,下面举一个很有意思的例子说明一下嵌套在解决复杂问题中比迭代更容易解决问题的例子:
有1个美国人,他有一枚祖传的1美元(100美分)硬币。有一天,他找到正在杂货店的我,对我我“嗨,哥们,你那有零钱吗”,“当然有”我回答道,“你要哪种,我这有50美分、25美分的、10美分的、5美分的和1美分的。”“这么多啊”他诧异道,“我想把1美分换成零钱,你能告诉我一共多少中不同的方式吗?”
当然对于这个刁难我的问题,我是不会回答他的,我立马叫来隔壁正在忙着破解美国军方网络的jack,“Hi,jack,help me”我大声叫道,jack却在忙着他手头的活,沉静了半分种,他晃了晃脑袋,说了句“I know what you want to say,wait me one miniter”,果然,不到一分钟,jack说了个数字292。当我还在雾里时,那位害我死了不少脑细胞的美国人大叫道:“不可思议,你是怎么做到的,我整整算了一周才把所有的情况排序出来”。聪明的你想到解决方案了吗。
使用递归到并不是很难实现,稍微动些脑筋。
数学描述是这样的:假设Fk(n)表述n美分兑换成k枚金币的所有结果,那么Fk(n)可以递归的看成,没有其中一种硬币的结果,和除去一个其中一种硬币的剩下钱的兑换结果,写成:Fk(n)=Fk-1(n)+Fk(n-a).
比如上面的例子可以描述成,最终结果是由(100美分去除一个50美分)剩余的50美分兑换成5种硬币的全部方法加上100美分兑换成4种硬币的方法(没有50美分的这种硬币)。图形可以更好的说明这一过程,聪明的你可以在纸上做一做图形。
但是,我想提醒的是,想把这一数学过程写成计算机代码并不是一件容易的事情,这里我先不给出Java语言的代码,你可以写出来,我们一下讨论一下。
当然这里有一个挑战留给大家,包括我自己,就是怎样把这个过程写成其他的方式,大家都知道,递归法是很消耗资源的,如果你设计出了更好的算法,请与我分享,[email protected]
谢谢!