看来你在要求这样的事情:
public class Fibonacci extends AbstractList<BigInteger> {
@Override
public Stream<BigInteger> stream() {
return Stream.iterate(new BigInteger[]{ BigInteger.ONE, BigInteger.ONE },
p->new BigInteger[]{ p[1], p[0].add(p[1]) }).map(p -> p[0]);
}
@Override
public Iterator<BigInteger> iterator() {
return stream().iterator();
}
@Override
public int size() {
return Integer.MAX_VALUE;
}
@Override
public BigInteger get(int index) {
return stream().skip(index).findFirst().get();
}
}
可以通过以下方式访问List
接口(它没有实现RandomAccess
有充分的理由),因此,您可以通过以下方式询问第 n 个值get(n)
。请注意,执行get
提示您如何获取之后位置的值Integer.MAX_VALUE
。只需使用stream().skip(position).findFirst().get()
.
谨防!这份清单是infinite,正如你所要求的。不要要求它对所有元素进行操作,例如甚至不toString()
。但像下面这样的事情将会顺利进行:
System.out.println(new Fibonacci().subList(100, 120));
or
for(BigInteger value: new Fibonacci()) {
System.out.println(value);
if(someCondition()) break;
}
但是,当您必须处理大型元素序列并希望高效地完成时,您应该确保在迭代器或流上工作,以避免O(n²)
重复的复杂性get
calls.
请注意,我将元素类型更改为BigInteger
因为当涉及到斐波那契数列和int
or long
值类型。即使与long
value 类型,仅 92 个值后序列就结束,发生溢出。
更新:既然你明确表示你正在寻找一个懒惰的人storage,您可以按如下方式更改上面的类:
public class Fibonacci extends AbstractList<BigInteger> {
final Map<BigInteger,BigInteger> values=new HashMap<>();
public Fibonacci() {
values.put(BigInteger.ONE, BigInteger.ONE);
values.put(BigInteger.ZERO, BigInteger.ONE);
}
@Override
public BigInteger get(int index) {
return get(BigInteger.valueOf(index));
}
public BigInteger get(BigInteger index) {
return values.computeIfAbsent(index, ix ->
get(ix=ix.subtract(BigInteger.ONE)).add(get(ix.subtract(BigInteger.ONE))));
}
@Override
public Stream<BigInteger> stream() {
return Stream.iterate(BigInteger.ZERO, i->i.add(BigInteger.ONE)).map(this::get);
}
@Override
public Iterator<BigInteger> iterator() {
return stream().iterator();
}
@Override
public int size() {
return Integer.MAX_VALUE;
}
}
I used BigInteger
作为这里的键/索引来满足(理论上)无限的要求,尽管我们可以使用long
也是所有实际用途的关键。关键点是最初为空的存储:(现在示例性地使用long
):
final Map<Long,BigInteger> values=new HashMap<>();
它是用应该结束每个递归的值预先初始化的(除非由于已经计算的值而提前结束):
values.put(1L, BigInteger.ONE);
values.put(0L, BigInteger.ONE);
然后,我们可以通过以下方式请求一个延迟计算值:
public BigInteger get(long index) {
return values.computeIfAbsent(index, ix -> get(ix-1).add(get(ix-2)));
}
或委托给的流get
上述方法:
LongStream.range(0, Long.MAX_VALUE).mapToObj(this::get);
这创建了一个“实际上无限”的流,而上面的完整示例类使用BigInteger
理论上是无限的……
The Map
将记住序列的每个计算值。