迭代與嵌套是面向過程的兩個非常有用的算法,在一些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]