利用Stream完成递归操作

先看一个最典型的递归应用场景:

public class Test4 {
    public static Long f(int n){
        if(n==1||n==2){
            return 1L;
        }else{
            return f(n-1)+f(n-2);
        }
    }

    public static void main(String[] args) {
        long now = System.currentTimeMillis();
        System.out.println(f(40));
        System.out.println("耗时:"+((System.currentTimeMillis()-now)/1000.0)+"秒");
    }
}

程序运行结果:102334155
耗时:4.672秒
如果将计算的个数提高到50的话
程序运行结果:12586269025
耗时:536.292秒

下面使用Stream来完成斐波那契数列的计算工作。
为了使递归计算更加的具有普适性,将从一个接口开始写起:

public interface Recursion<T> {

    Recursion<T> compute();

    default boolean isFinish(){return false;}

    default T result(){throw new UnsupportedOperationException("未实现的方法");}

    default T invoke(){

        return Stream.iterate(this,Recursion::compute)//试图产生一个无限序列,
                 //直到某一个Recursion对象通过filter测试
                //由于Lambda表达式“天生”的惰性,iterate每执行一次就会去调用filter验证一次
                //一旦通过filter验证就会立刻停止执行
                .filter(Recursion::isFinish)
                .findFirst()
                .get()//获得符合条件的Recursion对象
                .result();//调用它的result方法获得结果值

    }

然后写一个工具类Recursions方便一会儿递归调用发生时Recursion对象的产生

public class Recursions {

    public static<T> Recursion<T> call(Recursion<T> recursion){
        return recursion;
    }

    public static<T>  Recursion<T> done(T result){

        return new Recursion<T>(){

            @Override
            public Recursion<T> compute() {
                throw new UnsupportedOperationException("未实现的操作");
            }

            @Override
            public boolean isFinish() {
                return true;
            }

            @Override
            public T result() {
                return result;
            }
        };
    }

}

随后可以写一个测试方法和测试类:

public class Test5 {

    public static Recursion<Long> f(long l1,long l2,int count){
        if(count==1){
            return Recursions.done(l1);
        }else{
            return Recursions.call(f(l2,l1+l2,count-1));
        }
    }

    public static void main(String[] args) {
        long now = System.currentTimeMillis();
        Long s = f(1, 1, 50).invoke();
        System.out.println(s);
        System.out.println("耗时:"+((System.currentTimeMillis()-now)/1000.0)+"秒");
    }

}

代码运行后:
计算结果为:12586269025
耗时:0.128秒
Test5中与Test4中采用的递归算法并不一样。Test5中的f方法每一次“递归”时都会产生此时此刻的运算结果,然后利用该结果再次参与到下一次运算。
main方法中f(1, 1, 50).invoke(); invoke方法被调用前,f方法执行了50次,并最终返回了一个Recursion对象。注意该Recursion对象由Recursions工具类的done方法创建出来,它的compute方法并未提供具体实现一旦调用就会发生异常。但是当在该Recursion对象上调用invoke方法时,Strema序列iterate产生的无限序列的第一个元素(即Recursion对象本身)就符合filter的条件(该Recursion对象的isComplete方法返回true),因此根本不会通过调用该Recursion对象的compute方法去计算得到第二个序列中的内容,iterate方法就已经结束了。随后就是利用get方法将该Recursion对象从Stream序列中取出后,调用result方法获取计算结果。
本例中的Recursion接口和Recursions工具类在进行递归操作时具有一定的通用性,只要在应用场景中写好适当的测试方法即可,比如做一个累积的递归操作:

public class Test6 {

    public static Recursion<Long> f(long l , int count){
        if(count==1){
            return Recursions.done(l);
        }else{
            return Recursions.call(f(l*count,count-1));
        }
    }

    public static void main(String[] args) {
        System.out.println(f(1,5).invoke());
    }

}

程序运行结果为:120

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值