簡體   English   中英

Java記憶化

[英]Memoization in Java

好的,所以在C#中我可以這樣寫:

public class Memorizer<K,TRes>
{
    private Dictionary<K,TRes> _mem;
    private Func<K,TRes> _function

    public Memorizer (Func<K,TRes> function)
    {
        _function = function;
        _mem= new Dictionary<K,TRes>();
    }

    public TRes Call(K arg)
    {
        if (mem.ContainsKey(arg)
        {
            return _mem[arg];
        }
        else
        {
            TRes ret=_function(arg);
            _mem[arg] = ret;
            return ret;
        }
    }
}

可以利用它來獲得明顯的收益:

public class FactorialCalculator()
{
    private Memorizer<ushort, ulong> _memorizedFactorial;
    public FactorialCalculator()
    {
        _memorizedFactorial = new Memorizer<ushort, ulong> (innerFactorial);
    }

    private ulong innerFactorial(ushort x)
    {
        return (x=0) ? 1 : x*Factorial(x-1)
    }

    public ulong factorial(ushort x)
    {
        _memorizedFactorial.Call(x);
    }

}

我敢肯定它可以變得更普通,更優雅。 而且我知道如果x> 20,我會有溢出異常。 (而且我那里也可能有類型轉換錯誤)希望我能指出這一點:我可以創建一個可以滿足純數學函數(即確定性,無副作用的函數)的需求的類,並獲得出色的性能提升。

如何在Java中完成類似的任務?

在Java 8中,您可以使用computeIfAbsent實現備忘錄:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public class FactorialCalculator {

public static void main(String[] args) {

    Function<Integer, Long> factorialFunction = x -> {
        System.out.println("Calculating factorial for " + x);
        long fact = 1;
        for (int i = 1; i <= x; i++) {
            fact *= i;
        }
        return fact;
    };

    Function<Integer, Long> memoziedFactorialFunction = memoise(factorialFunction);

    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(6));
    System.out.println(memoziedFactorialFunction.apply(6));

}

public static <X, Y> Function<X, Y> memoise(Function<X, Y> fn) {
    Map<X, Y> pp = new ConcurrentHashMap<X, Y>();
    return (a) -> pp.computeIfAbsent(a, fn);
}

}

結果是:

Calculating factorial for 5
120
120
120
120
Calculating factorial for 6
720
720

更多詳細信息,請參見http://rdafbn.blogspot.ie/2015/06/memoize-functions-in-java-8.html

最后,您可以使用cyclops庫刪除創建備忘錄通用方法的樣板代碼(請參閱http://static.javadoc.io/com.aol.cyclops/cyclops-functions/4.0.2/com/aol /cyclops/functions/Memoise.html

查看Guava的緩存包。 這就是它的目的。

您不能在Java中將函數作為數據類型傳遞。 要解決此問題,請使用界面。

public interface ReturnFunction<K, V> {
    public V getValue(K k);
}

現在,您可以將innerFactorial設置為數據類型。

public ReturnFunction<Short, Long> innerFactorial = new ReturnFunction<Short, Long>(){
    public Long getValue(Short x){
        return (x=0) ? 1 : x*Factorial(x-1);
    }
};

這使您可以將innerFactorial作為數據類型傳遞:

_memoizedFactorial = new Memorizer<Short, Long> (innerFactorial);

並調用該函數,您可以這樣編寫:

long someLong = _memoizedFactorial.getValue(someShort);

另外,在Java中,請勿使用大寫的字段或方法名稱。 它不是標准的,使代碼更難閱讀。

您無法使用Java中的<short, ulong>創建通用映射<short, ulong>因為通用類型參數僅綁定到引用類型。 您必須將其設置為<Short, Long> ,其中涉及包裝原語,並且可能會給您的備忘錄帶來一些開銷。

除此之外,對Java的翻譯非常簡單。 請注意,您只能記住提供有用的equalshashCode實現的類型,並且需要使用大小限制,線程安全的弱鍵表,例如MapMaker提供的表。

暫無
暫無

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

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