【问题标题】:Memoization in JavaJava中的记忆
【发布时间】:2012-01-03 22:35:10
【问题描述】:

好的,所以我可以用 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 中完成类似的事情?

【问题讨论】:

  • 我相信这些被称为“memoizer”,而不是“memorizer”。
  • 也是Dictionary,而不是"new Dictionairy"行中的Dictionairy
  • 此外,基于素因数分解计算阶乘效率更高。对于每个素数 p
  • @Mike,这只是一个例子。证明一个观点。

标签: c# java performance function memoization


【解决方案1】:

查看 Guava 的 cache 包。这就是它的用途。

【讨论】:

  • 如果编译器或运行时可以为我们做备忘录,那将是一件很棒的事情。如果编译器/运行时可以安全地假设零副作用方法,那将是现实,不是吗?见tshrestha.blogspot.com/2013/04/…
【解决方案2】:

您不能在 Java 中从 &lt;short, ulong&gt; 创建泛型映射,因为泛型类型参数只绑定到引用类型。您必须将其设为 &lt;Short, Long&gt;,这涉及包装原语,并且可能会在您的记忆中引入一些开销。

除此之外,Java 的翻译非常简单。请注意,您只能记忆提供有用的equalshashCode 实现的类型,并且您需要使用诸如MapMaker 提供的大小有界、线程安全、弱键表。

【讨论】:

【解决方案3】:

您不能在 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 中不要大写字段或方法名称。它不标准,使代码更难阅读。

【讨论】:

  • 查看 Guava 的 Function 界面。无需重新发明轮子。
  • @John B Thanx 以前从未听说过,但很好。
  • 出于理论上的目的,并且因为不赞成为 3 行代码引入额外的 libnray。重新发明轮子并没有错。
  • 如果我想在一堂课中记住多个函数怎么办?我是否必须将每个包装在一个内部类实现函数中?还是有更优雅的方式?
  • and because introducting a extra libnray for 3 lines of code is frowned upon. There is nothing wrong with reinventing the wheel. 我不能再反对了。
【解决方案4】:

在 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 库删除创建 memoize 泛型方法的样板代码(查看http://static.javadoc.io/com.aol.cyclops/cyclops-functions/4.0.2/com/aol/cyclops/functions/Memoise.html

【讨论】:

    猜你喜欢
    • 2021-06-16
    • 2011-04-25
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    相关资源
    最近更新 更多