今天我从一些JS课程中学习了什么是memoization,并尝试用Java实现它。我有一个简单的递归函数来计算第n个斐波那契数:
long fib(long n) {
if (n < 2) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
然后我决定使用HashMap来缓存递归方法的结果:
private static <I, O> Function<I, O> memoize(Function<I, O> fn) {
final Map<I, O> cache = new HashMap<>();
return in -> {
if (cache.get(in) != null) {
return cache.get(in);
} else {
O result = fn.apply(in);
cache.put(in, result);
return result;
}
};
}
这正如我所期望的那样起作用了,它允许我像Thismemoize(This::fib)
那样,将fib()
进行memoize(This::fib)
然后我搜索了Java中的memoization主题,发现了一个问题:Java memoization方法,其中提出了computeifacent
,比我的条件表达式要短得多。
所以我希望工作的最终代码是:
public class FibMemo {
private final Function<Long, Long> memoizedFib = memoize(this::slowFib);
public long fib(long n) {
return memoizedFib.apply(n);
}
long slowFib(long n) {
if (n < 2) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
private static <I, O> Function<I, O> memoize(Function<I, O> fn) {
final Map<I, O> cache = new HashMap<>();
return in -> cache.computeIfAbsent(in, fn);
}
public static void main(String[] args) {
new FibMemo().fib(50);
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1134)
at algocasts.matrix.fibonacci.FibMemo.lambda$memoize$0(FibMemo.java:24)
at algocasts.matrix.fibonacci.FibMemo.fib(FibMemo.java:11)
at algocasts.matrix.fibonacci.FibMemo.slowFib(FibMemo.java:19)
at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1133)
at algocasts.matrix.fibonacci.FibMemo.lambda$memoize$0(FibMemo.java:24)
针对这个具体问题的最简单的使用站点解决方案是不使用ConcurrentHashMap,而只使用HashMap:
静态映射
这正是我想要做的,但在Java11中没有成功。我根据经验发现,HashMap从Java9开始抛出ConcurrentModificationException(感谢SDKMAN):
sdk use java 9.0.7-zulu && javac Test.java && java Test # throws ConcurrentModificationException
sdk use java 8.0.202-zulufx && javac Test.java && java Test # works as expected
我想知道为什么在尝试使用HashMap作为递归函数的缓存时会引发ConcurrentModificationException?是Java8中允许我这样做的一个bug,还是Java>9中抛出ConcurrentModificationException的另一个bug?
引发ConcurrentModificationException
是因为SlowFib
正在修改多个键和值。如果您查看Java9hashmap.computeIFENTACE()
代码,您会发现在下面抛出异常:
int mc = modCount;
V v = mappingFunction.apply(key);
if (mc != modCount) { throw new ConcurrentModificationException(); }
每次调用slowfib
都会尝试修改映射到键n-1
和n-2
的值。
在Java8HashMap.ComputeIfAstent()
代码中不执行modcount
检查。这是Java 8中的一个bug,您的方法并不能在所有情况下都起作用,因为根据JDK-8071667,hashmap.computeIFEstant()添加了hashmap.get()没有找到的条目,该条目在Java 9中添加了modcount
检查:
如果提供给ComputeIfAstant的函数将项添加到调用该函数的同一哈希表中,并且内部表因此而被放大,则新条目将添加到映射内部表中的错误位置,从而使其无法访问。
问题内容: 我有一个程序可以通过递归传递大量数据,例如1000个变量。递归将至少运行50或60次。我担心的是,由于没有足够的空间,是否有可能数据在内存位置上被覆盖,或者如果没有内存,那么我会得到一些例外,即程序内存已经用完(我没有收到这样的错误)? 是否存在错误的解决方案,因为该程序没有更多的内存并且在现有位置上被覆盖? 问题答案: 涉及两个存储区域:堆栈和堆。堆栈是保存方法调用的当前 状态 (即
来自Python的递归追加列表函数,试图递归地获取与文件结构相关的权限列表。 另一种情况是,A=允许,R=限制 输出将是[True,True,False,False,True,True,True]
问题内容: 我在大学为我的Programming II类编写的程序需要一些帮助。这个问题要求人们使用递归来计算斐波那契数列。必须将计算出的斐波那契数存储在一个数组中,以停止不必要的重复计算并减少计算时间。 我设法使程序在没有数组和存储的情况下运行,现在我试图实现该功能,但遇到了麻烦。我不确定如何组织它。我已经浏览了Google并浏览了一些书,但没有太多帮助我解决如何实施解决方案的方法。 上面是不正
“BASE”表示不只是使用LRU_Cache。所有这些都是“足够快的”--我不是在寻找最快的算法--但是时间让我吃惊,所以我希望我能学到一些关于Python是如何“工作”的东西。 现在很清楚了,我(和前面的许多人一样)只是偶然发现了Python的可变缺省参数。这种行为解释了执行速度的实际和明显的提高。
我有一个firebase函数尝试将数据写入firebase存储: 我在firebase日志中发现一个错误,它说: 错误类型错误[ERR_INVALID_ARG_TYPE]:“path”参数必须是string、Buffer或URL类型之一。接收类型对象 我怎么解决这个?