-
找到每个素数的倍数数,建立一个布尔数组,将倍数数改为true,表示为非素数,其余false表示为素数。
-
public static int eratost(int n){ boolean[] isPrime = new boolean[n];//建立一个布尔数组,将其值全部填充为false int count = 0; for(int i = 2;i < n;i++) { if(!isPrime[i]){ //若此标记位为false,则为素数,count+1 count ++; for(int j = 2 * i;j < n;j+=i){// j += i是因为,无法改变i的值,所以,j += i,可以让前面的2 * i之后加i,变为3 * i。 //在每一个i的倍数位上标记位true,表示为非素数 isPrime[j] = true; } } } return count; }
-
c语言同理
int main(void) { int n; scanf("%d",&n); int isPrime[100] = {0}; int count = 0; int i,j; for(i = 0;i<n;i++) { //由于c没有布尔数组,所以以整型数组中的0和1代替 isPrime[i] = 0; } for(i = 2;i<n;i++){ if(isPrime[i] == 0){ count ++; for(j = 2 * i;j<n;j+=i) { isPrime[j] = 1; } } } printf("%d\n",count); }
-
可以发现第二个循环的标记遍历为
2 * 2 | 3 * 2 | 4* 2 |
---|---|---|
2 * 3 | 3 * 3 | 4* 3 |
2 * 4 | 3 * 4 | 4* 4 |
2 * 5 | 3 * 5 | 4* 5 |
2 * 6 | 3 * 6 | 4* 6 |
2 * 7 | 3 * 7 | 4* 7 |
-
不难发现,中间有许多重复的标记选项,比如2 * 3和 3 * 2,所以,我们改动第二层循环,让其每次标记的乘数都从i开始,例如i如果为4,循环从4 * 4 开始,因为4之前的4 * 2 的值和 4 * 3 的值已经在i等于2时的2 * 4和等于3时的3 * 4时标记过了,已经改为true,所以没必要在遍历一次,所以我们可以将第二层循环的起始值改为j = i * i。
-
public static int eratost(int n){ boolean[] isPrime = new boolean[n]; int count = 0; for(int i = 2;i < n;i++) { if(!isPrime[i]){ count ++; for(int j = i * i;j < n;j+=i){ isPrime[j] = true; } } } return count; }