1. 程式人生 > >細談遞迴,備忘錄遞迴,動態規劃,三種演算法思想和執行原理

細談遞迴,備忘錄遞迴,動態規劃,三種演算法思想和執行原理

    大家都知道,數值稍大的遞迴執行時間對於開發者來說就是場災難,我們總是想方設法在優化遞迴,或者說不用遞迴,此文中從空間時間角度詳細剖析以上三種演算法的區別,以及執行原理,以斐波那契數為例, 程式語言java


此處為程式碼 
package test1;

import java.util.HashMap;

public class test2 {
    private static int count1=0;
    private static int count2=0;
    private static int count3=0;
    public static void
main(String[] args) { System.out.println("***********************遞迴*********************"); long startTime1=System.nanoTime(); System.out.println(getNumber1(30)); long endTime1=System.nanoTime(); System.out.println("方法呼叫了"+count1+"次數"); System.out.println("時間為:"
+(endTime1-startTime1)+"ns"); System.out.println("***********************備忘錄遞迴*********************"); long startTime2=System.nanoTime(); System.out.println(getNumber2(30)); long endTime2=System.nanoTime(); System.out.println("方法呼叫了"+count2+"次數"); System.out
.println("時間為:"+(endTime2-startTime2)+"ns"); System.out.println("***********************動態規劃*********************"); long startTime3=System.nanoTime(); System.out.println(getNumber3(30)); long endTime3=System.nanoTime(); System.out.println("方法呼叫了"+count3+"次數"); System.out.println("時間為:"+(endTime3-startTime3)+"ns"); } //遞迴 // 832040 // 方法呼叫了1664079次數 // 時間為:4839154ns public static int getNumber1( int m) { count1++; if(m==1||m==2) { return 1; } else return getNumber1(m-1)+getNumber1(m-2); } // 備忘錄演算法,自上而下,記住之前算過的值。減少方法的訪問次數從而減少執行時間 //方法呼叫了:57 //832040 //時間為:133048ns private static HashMap<Integer, Integer> hm=new HashMap<>(); public static int getNumber2( int m) { count2++; if(m==1||m==2) { return 1; } else if(hm.containsKey(m)) { return hm.get(m); } else { int value =getNumber2(m-1)+getNumber2(m-2); hm.put(m, value); return value; } } // 動態規劃,自下向上的演算法 //方法呼叫了:1 //時間為:3422ns //832040 public static int getNumber3( int m) { count3++; if(m==1||m==2) { return 1; } int a=1; int b=1; int temp=0; for(int x=3;x<=m;x++) { temp=a+b; a=b; b=temp; } return temp; } }
   先來說說第一種遞迴這是一種最常見的遞迴 也是最好理解的,在這裡我就不再贅述,原理和執行方式,只是提一句,這種遞迴是一種自上向下的遞推過程。而它的執行時間,以及呼叫次數如下。

這裡寫圖片描述
這裡寫圖片描述

   **這是當引數m為4的時候,由於此方法中只有一個m變數,在記憶體中執行的時候便不會佔用時間和空間,這是比備忘錄遞迴好的地方,當然這也僅僅侷限於當引數m小的時候,而隨著m的增大直到30,這時候顯而易見備忘錄遞迴的優勢就會體現出來,這時候在方法呼叫和執行時間上都有明顯的提升,如果說硬要有遜色的話,也就多佔了一個hashmap記憶體空間,不過這在8GB的執行記憶體中顯然不算什麼。**

其次,再來說說備忘錄遞迴的執行原理**
這裡寫圖片描述

    這是我在圖片編輯器中以引數m=4的時候為例畫出的程式碼流程圖,裡面詳細的介紹了整個備忘錄遞迴演算法的執行方向,介紹了hashmap如何存值,何時存值,如果細看的話,相信收穫頗豐。
    最後再來說說動態規劃把,關於它的定義我就不再多費口舌,簡單概述,自下而上,把整個數想成一個數組,把a[0]+a[1]的值放在a[2],然後a[1]+a[2]的值放在a[3],以此類推,只要一個迴圈就可以得出答案了。整個方法因為沒有遞迴的再呼叫,所以只被呼叫一次,從而大大減少了執行時間,