Java中遞迴和迴圈的優劣
介紹:
你用你手中的鑰匙開啟一扇門,結果去發現前方還有一扇門,緊接著你又用鑰匙打開了這扇門,然後你又看到一扇門......但是當你開到一扇門時,發現前方是一堵牆無路可走了,你選擇原路返回--這就是遞迴。
但是如果你開啟一扇門後,同樣發現前方也有一扇門,緊接著你又開啟下一扇門.....但是卻一直沒有碰到盡頭--這就是迴圈。
簡單來說:迴圈是有去無回,而遞迴是有去有回(因為存在終止條件)。
迴圈:當滿足某一條件時反覆執行某一操作(迴圈體)。
遞迴:在一個方法內部對自身進行呼叫的方法。
遞迴結構包括兩個部分:
1、遞迴頭:即什麼時候不呼叫自身方法,也就是遞迴的結束條件。如果沒有遞迴頭,程式將陷入死迴圈。
2、遞迴體:即什麼時候需要呼叫自身方法。
好了,廢話不多說,直接來擼程式碼(計算階乘的方法)。
package com.bjwyj.method; /** * 遞迴和迴圈的比較 * @author 吳永吉 * */ public class TestRecursion { public static void main(String[] args) { //以下呼叫System下的currentTimeMillis()方法只是為了說明遞迴呼叫比迴圈呼叫更耗時 long l1 = System.currentTimeMillis(); System.out.println(factorial(5)); long l2 = System.currentTimeMillis(); System.out.println("遞迴計算階乘耗時:"+(l2-l1)); System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"); long time1 = System.currentTimeMillis(); System.out.println(factorialLoop(5)); long time2 = System.currentTimeMillis(); System.out.println("迴圈計算階乘耗時:"+(time2-time1)); } //使用遞迴定義計算階乘的方法 public static long factorial(int num) { if(num==1) {//遞迴頭 return 1; }else { return num*factorial(num-1);//遞迴體 } } //使用迴圈定義計算階乘的方法 public static long factorialLoop(int n) { int result = 1;//接收計算結果 while(n>1) { result *= n*(n-1);//實現計算結果的累乘操作 n -= 2;//每次減去2,實現數字的迭代操作 } return result; } }
執行結果:
120 遞迴計算階乘耗時:1 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 120 迴圈計算階乘耗時:0
由結果可以看出,使用遞迴演算法比使用迴圈演算法更耗時。
為了更好地比較遞迴演算法的優劣,上述採用while迴圈與遞迴演算法進行對比。
先來分析上述遞迴方法的執行過程,如下圖:
迴圈方法的執行過程,如下圖:
這裡為了看起來清晰,只是簡單地畫出了棧記憶體中的執行過程(這樣畫更便於理解)。
總結:
棧,主要是用來存放棧幀的,每執行一個方法就會出現壓棧操作,所以採用遞迴的時候產生的棧幀比較多,遞迴就會影響到記憶體,非常消耗記憶體。而使用迴圈就執行了一個方法,壓入棧幀一次,只存在一個棧幀,所以比較節省記憶體。