java 8 中的质数
Prime number in java 8
我试图在 Java8 中编写一个简单的素数程序。下面是程序。我也想减少 isPrime()
中的代码。是否有东西可以过滤从 2
到 n/2
的元素,然后对 n%i == 0
应用过滤器,这会使 isPrime
变得无关紧要?
import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Stream1 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 20);
// Prime number
System.out.println(numbers.stream()
.filter(Stream1::isPrime)
.collect(toList()));
}
public static boolean isPrime(int number) {
for (int i = 2; i <= number / 2; i++) {
if (number % i == 0) {
return false;
}
}
return true;
}
}
IntStream可用于生成整数流
public static boolean isPrime(int number) {
return !IntStream.rangeClosed(2, number/2).anyMatch(i -> number%i == 0);
}
或
public static boolean isPrime(int number) {
return IntStream.rangeClosed(2, number/2).noneMatch(i -> number%i == 0);
}
您的 isPrime()
效率低下。首先,您不需要除以任何大于 2 的偶数,因为初始除以 2 将捕获所有偶数非素数。其次,您在 number / 2
而不是更有效的 sqrt(number)
.
处终止循环
您可以像这样重写您的方法:
public static boolean isPrime(int number) {
// Even numbers
if (number % 2 == 0) {
return number == 2;
}
// Odd numbers
int limit = (int)(0.1 + Math.sqrt(number));
for (int i = 3; i <= limit; i += 2) {
if (number % i == 0) {
return false;
}
}
return true;
}
Eratosthenes 筛法会更有效,但对于相对较小的问题来说,这可能有点过分了。
正如@rossum 所建议的,您可以为此使用著名的 Sieve of Eratosthenes,它会非常快速地计算素数。
private static BitSet primes(int limit) {
BitSet bitSet = new BitSet(limit);
bitSet.set(0, false);
bitSet.set(1, false);
bitSet.set(2, limit, true);
for (int i = 2; i * i < limit; ++i) {
if (bitSet.get(i)) {
int j = i;
int x = 2;
while (j < limit) {
j = i * x;
bitSet.set(j, false);
++x;
}
}
}
return bitSet;
}
您也可以使用 predicate 来达到预期效果。
import java.util.Arrays;
import java.util.List;
import java.util.function.IntPredicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class PrimeUsingStream {
public static boolean isPrime(int i) {
IntPredicate isDivisible = index -> i % index == 0;
return i > 1 && IntStream.range(2, i).noneMatch(isDivisible);
}
public static void main(String[] args)
{
//System.out.println(printPrime(200));
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 20,23);
// Prime number
System.out.println(numbers.stream()
.filter(PrimeUsingStream::isPrime)
.collect(Collectors.toList()));
}
}
您可以使用流作为下面的测试:
@Test
public void generatePrimeNumberListByStream(){
List<Integer> primeNumbers =
IntStream
.range(2,30)
.filter(number -> IntStream.range(2,number)
.noneMatch(divider -> number % divider == 0))
.boxed()
.collect(Collectors.toList());
assertThat(primeNumbers, contains(2,3,5,7,11,13, 17,19, 23, 29));
}
你可以像这样使用算法Sieve of Eratosthenes
public static IntStream primes(int max) {
IntStream primes = IntStream.range(2, max);
IntFunction<IntPredicate> sieve = n -> i -> i == n || i % n != 0;
primes = primes.filter(sieve.apply(2));
for (int i = 3; i * i <= max; i += 2)
primes = primes.filter(sieve.apply(i));
return primes;
}
和
System.out.println(primes(100).count()); // -> 25
System.out.println(primes(1000).count()); // -> 168
System.out.println(primes(10000).count()); // -> 1229
public static boolean isPrime(int i) {
return i % 2 != 0 && IntStream.iterate(
3, n -> n <= (int)(Math.sqrt(i)), n -> n + 2)
.noneMatch(k->i%k==0);
}
iterate有3个参数,类似for循环,base是开始,第二个是停止条件,第三个是自增规则。
1 和 2 已经是质数,所以我们从 3 开始,在达到数字的平方根之前停止。这个想法是假设n是一个正整数n=pq,其中p和q是素数。假设 p 大于 n 的平方根且大于 n 的平方根。将这些不等式相乘,我们得到 p*q > sqrt n * sqrt n,这意味着 pq > n。这与我们的假设 n=pq 相矛盾。因此我们可以得出结论,p 小于或等于 sqrt n 或 q 小于等于 sqrt n.
n -> n <= (int)(Math.sqrt(i))
最后我们不需要检查偶数,只要它不能被 2 整除,所以我们只尝试每隔一个数字。
(n -> n+2)
Java8+解法
public static boolean isPrime(long number) {
return number>1 && LongStream.rangeClosed(2, number / 2).noneMatch(i -> number % i == 0);
}
需要排除1!!
A prime number (or a prime) is a natural number greater than 1 that is not a product of two smaller natural numbers.
public static void main(String[] args) {
List<Integer> list = IntStream.range(0, 100).filter(i -> isPrime(i)).boxed().collect(Collectors.toList());
System.out.println(list);
}
static boolean isPrime(int number) {
return number > 1 && IntStream.rangeClosed(2, number/2).noneMatch(i -> number % i == 0);
}
我试图在 Java8 中编写一个简单的素数程序。下面是程序。我也想减少 isPrime()
中的代码。是否有东西可以过滤从 2
到 n/2
的元素,然后对 n%i == 0
应用过滤器,这会使 isPrime
变得无关紧要?
import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Stream1 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 20);
// Prime number
System.out.println(numbers.stream()
.filter(Stream1::isPrime)
.collect(toList()));
}
public static boolean isPrime(int number) {
for (int i = 2; i <= number / 2; i++) {
if (number % i == 0) {
return false;
}
}
return true;
}
}
IntStream可用于生成整数流
public static boolean isPrime(int number) {
return !IntStream.rangeClosed(2, number/2).anyMatch(i -> number%i == 0);
}
或
public static boolean isPrime(int number) {
return IntStream.rangeClosed(2, number/2).noneMatch(i -> number%i == 0);
}
您的 isPrime()
效率低下。首先,您不需要除以任何大于 2 的偶数,因为初始除以 2 将捕获所有偶数非素数。其次,您在 number / 2
而不是更有效的 sqrt(number)
.
您可以像这样重写您的方法:
public static boolean isPrime(int number) {
// Even numbers
if (number % 2 == 0) {
return number == 2;
}
// Odd numbers
int limit = (int)(0.1 + Math.sqrt(number));
for (int i = 3; i <= limit; i += 2) {
if (number % i == 0) {
return false;
}
}
return true;
}
Eratosthenes 筛法会更有效,但对于相对较小的问题来说,这可能有点过分了。
正如@rossum 所建议的,您可以为此使用著名的 Sieve of Eratosthenes,它会非常快速地计算素数。
private static BitSet primes(int limit) {
BitSet bitSet = new BitSet(limit);
bitSet.set(0, false);
bitSet.set(1, false);
bitSet.set(2, limit, true);
for (int i = 2; i * i < limit; ++i) {
if (bitSet.get(i)) {
int j = i;
int x = 2;
while (j < limit) {
j = i * x;
bitSet.set(j, false);
++x;
}
}
}
return bitSet;
}
您也可以使用 predicate 来达到预期效果。
import java.util.Arrays;
import java.util.List;
import java.util.function.IntPredicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class PrimeUsingStream {
public static boolean isPrime(int i) {
IntPredicate isDivisible = index -> i % index == 0;
return i > 1 && IntStream.range(2, i).noneMatch(isDivisible);
}
public static void main(String[] args)
{
//System.out.println(printPrime(200));
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 20,23);
// Prime number
System.out.println(numbers.stream()
.filter(PrimeUsingStream::isPrime)
.collect(Collectors.toList()));
}
}
您可以使用流作为下面的测试:
@Test
public void generatePrimeNumberListByStream(){
List<Integer> primeNumbers =
IntStream
.range(2,30)
.filter(number -> IntStream.range(2,number)
.noneMatch(divider -> number % divider == 0))
.boxed()
.collect(Collectors.toList());
assertThat(primeNumbers, contains(2,3,5,7,11,13, 17,19, 23, 29));
}
你可以像这样使用算法Sieve of Eratosthenes
public static IntStream primes(int max) {
IntStream primes = IntStream.range(2, max);
IntFunction<IntPredicate> sieve = n -> i -> i == n || i % n != 0;
primes = primes.filter(sieve.apply(2));
for (int i = 3; i * i <= max; i += 2)
primes = primes.filter(sieve.apply(i));
return primes;
}
和
System.out.println(primes(100).count()); // -> 25
System.out.println(primes(1000).count()); // -> 168
System.out.println(primes(10000).count()); // -> 1229
public static boolean isPrime(int i) {
return i % 2 != 0 && IntStream.iterate(
3, n -> n <= (int)(Math.sqrt(i)), n -> n + 2)
.noneMatch(k->i%k==0);
}
iterate有3个参数,类似for循环,base是开始,第二个是停止条件,第三个是自增规则。 1 和 2 已经是质数,所以我们从 3 开始,在达到数字的平方根之前停止。这个想法是假设n是一个正整数n=pq,其中p和q是素数。假设 p 大于 n 的平方根且大于 n 的平方根。将这些不等式相乘,我们得到 p*q > sqrt n * sqrt n,这意味着 pq > n。这与我们的假设 n=pq 相矛盾。因此我们可以得出结论,p 小于或等于 sqrt n 或 q 小于等于 sqrt n.
n -> n <= (int)(Math.sqrt(i))
最后我们不需要检查偶数,只要它不能被 2 整除,所以我们只尝试每隔一个数字。
(n -> n+2)
Java8+解法
public static boolean isPrime(long number) {
return number>1 && LongStream.rangeClosed(2, number / 2).noneMatch(i -> number % i == 0);
}
需要排除1!!
A prime number (or a prime) is a natural number greater than 1 that is not a product of two smaller natural numbers.
public static void main(String[] args) {
List<Integer> list = IntStream.range(0, 100).filter(i -> isPrime(i)).boxed().collect(Collectors.toList());
System.out.println(list);
}
static boolean isPrime(int number) {
return number > 1 && IntStream.rangeClosed(2, number/2).noneMatch(i -> number % i == 0);
}