良好的数据结构和算法知识是成为一个更好的程序员的第一步。为了延续这个传统,今天我将分享一个有趣的算法,Eratosthenes算法的Sieve,它可以用来生成质数直到给定的数字。在很多情况下,你需要生成指定整数的所有素数,而最常用于生成素数的算法是Eratosthenes算法的 Sieve。但是很少有开发人员知道这个算法,特别是Java程序员,这主要是因为没有进行足够的竞争性编程。
Eratosthenes Sieve of Eratosthenes是一种古希腊算法,用于查找给定数字之前的所有素数,以希腊著名数学家Eratosthenes的名字命名。他是第一个计算地球周长的人,也因研究历法闰年而闻名。
素数是一个整数,它可以被1整除也可以像2 3 5这样被自身整除,而不能被任何正整数整除。
换句话说,素数不具有1或其自身的因子。可以使用此算法生成从1到100或任意最大值的素数。
在本文中,不仅将学习Eratosthenes Sieve算法的工作原理,还将使用该算法生成素数,并验证生成的所有数是否都是素数。
Eratosthenes算法的Sieve如何工作
Eratosthenes算法的Sieve非常简单。可以通过指定的整数创建大于1的数组,以便该数组的索引表示存储在其上的实际整数。然后从2开始,因为0和1不被认为是素数。
素数要么能被1整除要么能被自身整除,它没有其他因数。因为2是素数,我们把它标记为素数然后划掉所有倍数因为它们不是素数,为什么?因为素数不具有除1之外的任何因子,并且如果数字是2的倍数,则意味着它可以被2整除,因此不是素数。
为了越过所有乘以2的数字,我们只是将数组计数器跳过2,这意味着2,4,6,8都是2的倍数,它们将被交叉。数组中的下一个数字是3,现在3也不能被任何人整除,因此它是素数,我们将其标记为素数,并再次划掉所有3的倍数,因为它们不是素数。
为了超过3的倍数,我们跳过数组计数器3,这意味着3,9,12,15都是交叉的。现在,下一个数字是4但它已经越过,因为它是2的倍数所以我们跳到下一个数字是5。
5是素数,所以我们将它标记为素数,并将所有5的倍数交叉,因为它们不会是素数,它们可以被5整除。为了跨越5的所有倍数,我们只增加数组计数器按5,所以数字如10,15,20,25将被划掉。
我们继续这个过程,直到达到给定数字的平方根,因为数组中的每个倍数都有一个小于或等于给定数字的平方根的素数因子,所以我们不必交叉出倍数大于该根的数字 例如,为了找到1到100之间的所有素数,它足以检查到10。
Java中Eratosthenes算法实现的筛选
这是我们的Java程序,它使用Java编程语言中的Eratosthenes算法Sieve实现生成素数的逻辑:
import org.junit.Test;
import static org.junit.Assert.*;
/**
*此类使用以下内容生成达到给定限制的素数
* Eratosthenes算法筛选。在这个算法中,我们创建了
*从2开始的整数数组,然后找到第一个未交叉的整数
*整数,并将其全部交叉。重复该过程
*直到阵列中没有多个倍数。
*/
public class PrimeNumberGenerator {
private enum Marker{
CROSSED, UNCROSSED;
}
private static Marker[] crossedOut;
private static int[] primes;
public static int[] generatePrimeNumbersUpto(int limit){
if(limit < 2){
return new int[0];
}else{
uncrossIntegerUpto(limit);
crossOutMultiples();
putUncrossedIntegersIntoPrimes();
return primes;
}
}
private static void uncrossIntegerUpto(int limit) {
crossedOut = new Marker[limit + 1];
for(int i = 2; i
crossedOut[i] = Marker.UNCROSSED;
}
}
private static void crossOutMultiples() {
int iterationLimit = determineIterationLimit();
for (int i = 2; i<= iterationLimit; i++){
if(notCrossed(i)){
crossOutMultipleOf(i);
}
}
}
private static int determineIterationLimit() {
//数组中的每个倍数都有一个素数因子
//小于或等于平方根
//数组大小,我们不需要越过
//大于根的倍数。
double iterationLimit = Math.sqrt(crossedOut.length);
return (int) iterationLimit;
}
private static boolean notCrossed(int i) {
return crossedOut[i] == Marker.UNCROSSED;
}
private static void crossOutMultipleOf(int i) {
for(int multiple = 2*i;
multiple < crossedOut.length;
multiple += i){
crossedOut[multiple] = Marker.CROSSED;
}
}
private static void putUncrossedIntegersIntoPrimes() {
primes = new int[numberOfUncrossedIntegers()];
for(int j = 0, i = 2; i
if(notCrossed(i)){
primes[j++] = i;
}
}
}
private static int numberOfUncrossedIntegers() {
int count = 0;
for(int i = 2; i
if(notCrossed(i)){
count++;
}
}
return count;
}
}
在Java中检查Prime数的单元测试
下面是一些单元测试,用于检查我们的程序是否正常工作
import static org.junit.Assert.*;
import org.junit.Test;
/** * Junit测试用例来测试我们的Eratosthenes Sieve算法
* 用于生成一个给定整数的素数
* */
public class PrimeNumberGeneratorTest{
public PrimeNumberGeneratorTest(){
System.out.println("Generator prime numbers using"
+ " Sieve of Eratosthenes algorithm");
}
@Test
public void testPrimes(){
int[]primeUptoZero = PrimeNumberGenerator.generatePrimeNumbersUpto(0);
assertEquals(0, primeUptoZero.length);
int[] primeUptoTwo = PrimeNumberGenerator.generatePrimeNumbersUpto(2); assertEquals(1, primeUptoTwo.length);
assertEquals(2, primeUptoTwo[0]);
int[] primeUptoThree = PrimeNumberGenerator.generatePrimeNumbersUpto(3); assertEquals(2, primeUptoThree.length);
assertEquals(2, primeUptoThree[0]);
assertEquals(3, primeUptoThree[1]);
int[]primeUptoHundred=PrimeNumberGenerator.generatePrimeNumbersUpto(100);
assertEquals(25, primeUptoHundred.length);
assertEquals(97, primeUptoHundred[24]);
}
@Test
public void testExhaustive(){
for(int i = 2; i<700; i++){ verifyPrimeList(PrimeNumberGenerator.generatePrimeNumbersUpto(i));
}
}
private void verifyPrimeList(int[] listOfPrimes) {
for(int i = 0; i
verifyPrime(listOfPrimes[i]);
}
}
private void verifyPrime(int number) {
for (int factor = 2; factor < number; factor++){
assertTrue(number%factor != 0);
}
}
}
这是我们单元测试的结果,全部通过了
这就是如何使用Sieve of Eratosthenes算法生成高达指定整数的素数。这是生成大量素数的非常有效的算法,可用于解决需要素数数组的复杂编程问题。