Java Stream来写算法06——使用两个数据流查找孪生素数

16 篇文章 0 订阅
16 篇文章 0 订阅

总目录

这一系列的文章旨在探讨如何最小化使用循环语句,尽最大可能使用Java Stream来完成有趣的与数学相关的运算。
之前的文章讲解了如何查找到素数,对素数而言,其中还有一个孪生素数的问题非常有趣,美籍中国数学家张益唐在前几年,在其五十多岁“高龄”完成了以往只能由二、三十岁年轻数学家才能完成的孪生素数性质证明,而震惊了世界。
所谓“孪生素数”是指,类似3和5,11和13,17和19这样的,两个同时为素数,这两个数只相差2的数字对

难点

  • 使用Java Stream来处理这个问题的一个难点就是,Java数据流是无状态的,它没有顺序,没有前后,只有一个个单独出现的数据,从而使得查找有特定性质的单个数据时可能会很容易,但要想根据前一个数据来查看下一个数据就要很困难
  • 对于这个问题,可以使用Stream的生成器来解决,生成器,生成的数据就是有天然顺序的,但是根据前一个值,来查找下一个值却是一个坎啊

判断素数的流代码

IntPredicate intPredicate = v -> {
    if (v == 2 || v == 3 || v == 5) return true;
    if (v % 2 == 0) return false;
    int sqrtValue = Double.valueOf(Math.sqrt(v)).intValue();
    return !(IntStream.iterate(3, oddValue -> oddValue + 2).limit(sqrtValue).parallel()
            .filter(v1 -> v1 <= sqrtValue).anyMatch(v1 -> v % v1 == 0));
};
  • 这是一个使用lambda表达式来返回一个IntPredicate接口的实例,这个接口的实现代码,是为了判断传入的参数是不是素数。如果是返回true,如果不是返回false
  • 这段代码内容的详细解释可以参看之前的文章,这里就不再赘述了

如何让流可以感知上一次生成的值内容

  • 孪生素数,首先要知道上一个值如果是素数,然后再判断当前的值是不是素数,如果都是就是孪生素数
  • Java数据流生成器,是典型的熊瞎子,生成一个数,就抛弃一个数,只管生产,其他一概不再过问
  • 所以通过单个流是根本没有办法知道上一个生成值的内容的
  • 既然一个流不行,那就用两个流,stream1和stream2,这两个流每生成一个数据,就开始判断是不是相差为2的素数,如果是,妥妥的素数对就生成了
  • 那么这两个数据流的内容就是关键了,首先,生成数据流,内容是奇数(偶数肯定不是素数)流,再将其筛选为只含有素数,内容如下
1234567……
stream12357111317
stream235711131719
  • 表格中第一行,是生成数列的顺序号,由于是生成器生成,所以有这个天然的顺序号
  • 将相同顺序号的两个值,组成数据对,判断是不是相差为2
  • 接下来的难点就是如何取得同样顺序号中的两个流中的值了
  • 解决这个问题的方案就是遍历流中的数据了iterator

主代码

private void getTwinPrimeWithTwoStream() {
    IntStream intStream1 = IntStream.concat(
            IntStream.of(2, 3, 5),
            IntStream.iterate(7, i -> i + 2).filter(intPredicate));
    IntStream intStream2 = IntStream.concat(
            IntStream.of(3, 5),
            IntStream.iterate(7, i -> i + 2).filter(intPredicate));
    PrimitiveIterator.OfInt iterator1 = intStream1.iterator();
    PrimitiveIterator.OfInt iterator2 = intStream2.iterator();
    int count = 0;
    while (iterator1.hasNext()) {
        if (iterator2.hasNext()) {
            int v1 = iterator1.next();
            int v2 = iterator2.next();
            if ((v2 - v1) == 2) {
                System.out.printf("%,5d:%,d---%,d\n", ++count, v1, v2);
            }
        }
    }
}
  • 在生成两个数据流前,是使用硬编程的方式的把2、3、5硬插入到流中,非如此,无法准确判断出是是素数,这是intPredicate这个函数式接口实现中的缺陷,因为只有这三个数,所以没必要为了这三个数而把整个逻辑大改变
  • 上述代码生成的无限流,也就是如果任其运行,是可以把64位(与计算机位数有关)长度的整数中全部素数对查找出来
  • 如果限制其长度,加入在两个流中加入limit(长度值)即可,具体代码写法可以参见之前文章
  • 通过代码运行的效果,可以知道这两个流的生成是在另外的线程中,因为while语句的执行,是根本不受阻碍的
  • 这个代码的缺憾就是使用了while语句,这也是遍历数据流的,目前个人已知的唯一方法,如果有更好方法,还望不吝赐教
  • 这是用两个流来生成素数对,下一篇再写如何用一个流来生成素数对
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值