簡體   English   中英

Java遞歸方法記憶

[英]Java Memoization of Recursive method

我正在嘗試創建階乘函數的記憶版本。 當我調用factMemoized(4)時,它第一次計算階乘4並將其存儲在Map中。 當我再次調用factMemoized(4)時,它現在給出存儲的結果,而不是再次重新計算。 這按預期工作。 但是,當我調用factMemoized(3)時,即使它已經計算出fact(3)作為計算fact(4)的一部分,它也會重新計算該值。 有什么方法可以確保即使在遞歸調用中計算出的值也可以存儲在映射中,而無需在fact()函數中添加備注功能?

import java.util.HashMap;
import java.util.Map;


public class MemoizeBetter {

public static <F, T> Function<F, T> memoize(final Function<F, T> inputFunction) {
    return new Function<F, T>() {
      // Holds previous results
      Map<F, T> memoization = new HashMap<F, T>();

      @Override
      public T apply(final F input) {
        // Check for previous results
        if (!memoization.containsKey(input)) {
          // None exists, so compute and store a new one

          memoization.put(input, inputFunction.apply(input));
        }else{
            System.out.println("Cache hit:"+input);
        }

        // At this point a result is guaranteed in the memoization
        return memoization.get(input);
      }
    };
  }

public static void main(String args[]){


final Function<Integer, Integer> fact = new Function<Integer, Integer>() {
      @Override
      public Integer apply(final Integer input) {
        System.out.println("Fact: " + input);
        if(input == 1)
            return 1;
        else return input * apply(input -1);

      }
    };

    final Function<Integer, Integer> factMemoized = MemoizeBetter.memoize(fact);

    System.out.println("Result:"+ factMemoized.apply(1));
    System.out.println("Result:"+factMemoized.apply(2));
    System.out.println("Result:"+factMemoized.apply(3));
    System.out.println("Result:"+factMemoized.apply(2));
    System.out.println("Result:"+factMemoized.apply(4));
    System.out.println("Result:"+factMemoized.apply(1));    }    
}

interface Function<F,T>{
    T apply(F input);
}

問題是您的階乘函數不會以遞歸方式調用該函數的記憶版本。

要解決此問題,有一些選擇。

  1. 您可以參數化階乘函數,並為其引用應遞歸調用的Function 在未記憶的情況下,這將是函數本身; 在有記憶的情況下,這將是有記憶的包裝器。

  2. 您可以通過擴展階乘函數類,重寫而不是委托給未存儲的apply()來實現備忘錄。 這是很難做到的,但是有實用程序可以動態創建子類(例如,這是實現AOP的一種常用方法)。

  3. 您可以從基本功能開始就全面了解備忘錄。

這是第一種選擇的要點:

interface MemoizableFunction<I, O> extends Function<I, O> {

    //in apply, always recurse to the "recursive Function"
    O apply(I input);

    setRecursiveFunction(Function<? super I, ? extends O>);
}

final MemoizableFunction<Integer, Integer> fact = new MemoizableFunction<Integer, Integer>() {

  private Function<Integer, Integer> recursiveFunction = this;

  @Override
  public Integer apply(final Integer input) {
    System.out.println("Fact: " + input);
    if(input == 1)
        return 1;
    else return input * recursiveFunction.apply(input -1);
  }

  //...
};

解決此問題的另一種方法是使用數組存儲已經計算出的斐波那契值。 它的工作方式是,如果在數組的第n個索引處存在第n個位置的斐波那契,則不會再次計算該值,而只是從數組中選取該值。

但是,如果該值在數組中的第n個位置不存在,則將對其進行計算。 下面給出的是這種方法fibonacci()的代碼-

public static long fibonacci(long n){
    long fibValue=0;
    if(n==0 ){
        return 0;
    }else if(n==1){
        return 1;
    }else if(fibArray[(int)n]!=0){
        return fibArray[(int)n];    
    }
    else{
        fibValue=fibonacci(n-1)+fibonacci(n-2);
        fibArray[(int) n]=fibValue;
        return fibValue;
    }
}

請注意,此方法使用全局(類級別)靜態數組fibArray []。 要查看帶有解釋的整個代碼,您還可以看到以下內容-http: //www.javabrahman.com/gen-java-programs/recursive-fibonacci-in-java-with-memoization/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM