遞歸與分治策略(一)java
簡而言之,遞歸就是本身調用本身。算法
遞歸算法:直接或者間接地調用自身的算法。函數
遞歸函數:用函數自身給出定義的函數。性能
注意:每一個遞歸函數都必須有非遞歸定義的初始值,以確保遞歸函數完成計算。測試
下面經過兩個例子來介紹遞歸的特色spa
例1 階乘函數code
階乘函數遞歸地定義爲:blog
n!=1 (n=0) 排序
或者 遞歸
n!=n(n-1)! (n>0)
下面用一段簡單的Java代碼實現
這裏是遞歸實現:
public static int facterial(int n) { if (n == 0) return 1; else if (n < 0) return -1;//發生異常,退出 else return n * facterial(n - 1); }
下面是迭代實現:
public static int f(int n) { if (n == 0) return 1; else if (n < 0) return -1;//發生異常,退出 else { for (int i = n - 1; i >= 1; i--) { n *= i; } return n; } }
分析比較一下兩種實現方法:
遞歸實現:時間複雜度O(n);空間複雜度O(n)。
迭代實現:時間複雜度O(n);空間複雜度O(1)。
比較可知兩種實現的時間複雜度等價,空間複雜度遞歸佔用的略大一下,可是代碼的結構清晰度遞歸更清晰一些。
下面進行第二個例子的講解
例2 Fibonacci數列
Fibonacci數列的遞歸定義爲
F(n)=1 (n=0,1)
或者
F(n)=F(n-1)+F(n-2) (n>1)
下面用一段簡單的Java代碼實現
這裏是遞歸實現:
public static int fibonacci(int n ){ if(n<0) return -1; //發生異常,退出 else if(n<=1) return 1; else return fibonacci(n-1)+fibonacci(n-2); }
下面是迭代實現:
public static int F(int n){ if(n<0) return -1; //發生異常,退出 else if(n<=1) return 1; else { int f0=1,f1=1,fx=0; for(int i=2;i<=n;i++){ fx=f0+f1; f0=f1; f1=fx; } return fx; } }
分析比較一下兩種實現方法:
遞歸實現:時間複雜度O(1.618的n次方);空間複雜度O(n)。
迭代實現:時間複雜度O(n);空間複雜度O(1)。
比較可知遞歸實現的時間複雜度已經很是大了,空間複雜度遞歸佔用的略大一下,可是代碼的清晰度遞歸更清晰一些。而真正使用起來遞歸實現的代碼是無用代碼,用n=40這個數測試一下便知,遞歸實現的耗時太長了,有興趣的能夠測試一下。
下面概括一下遞歸算法的特色:
1.簡單(結構清晰,可讀性強)
2.性能較低(相比較迭代而言)
性能較低的緣由有如下兩點:
1 需遞歸調用工做棧支持(沒法避免)
2 有可能出現子問題重疊現象(必須盡力避免)
這裏遞歸的主要知識點就講完了,下面介紹一下文章標題的分治法。
分治法的基本思想:
(容易)分解->遞歸->(容易)合併
分解:講一個大規模的問題分解爲多個規模較小的子問題,須要注意的是子問題必須互相獨立而且與原問題相同。
這裏用一個例子進行講解:歸(合)並排序。
這裏留在下一篇文章介紹,睡覺咯,今天學到了這些,和你們分享一下,感謝你們的支持。