求 0-N 内有多少个素数

   问题:求 0-N 内素数的个数。

预备知识

  1. 什么是素数:素数(又叫质数),与之相反的是合数。素数的因数只有 1他本身,例如:7 = 1 * 7。而 6 = 1 * 6 = 2 * 3,因此6不是素数。 规定:0 和 1 既不是 素数 也不是 合数。
  2. 判断素数:如果一个数 x 是素数,那么在整数范围 [2,√x ] 之间,找不到任何能整除x 的整数。为什么只需要尝试到 √x ,而不是 n-1 呢?(肯定不是n呀,因为n是他本身,判断 n 就和判断 1 一样,没有意义的)。
  3. √x 的由来:一个正数 n ,可以表示成:n = √n * √n 。n 的两个因数有以下两种可能:? 两个因数都为 √n ?一个因数大于 √n,另一个因数一定小于 √n。如果我们在 2 到 √n 之间找不到一个因数的话,那么对应的在 √n 到 n-1 的范围内 绝对也找不到另外一个因数。而素数所期待的不正是 2 到 n-1 的范围内找不到两个因数,只希望因数为 1 和 n 吗?

阶段一

 1 public void countPrime_1(int n) {
 2
 3         // 之所以数组范围设置为 n+1,是因为数组从下标为 1 开始计数,n表示最后一个数
 4         // 数组初始值为false,因为我们假设false代表是素数,true代表不是素数
 5         boolean[] b = new boolean[n + 1];
 6
 7         // 2 - n 每个数逐一判断
 8         for (int i = 2; i <= n; i++) {
 9             // 【2,√i】
10             for (int j = 2; j * j <= i; j++) {
11                 if (i % j == 0) {
12                     // 在判断 i 是否为素数的过程中,遍历 2 - √i
13                     // 一旦发现在【2,√i】中,有数整除了,将数组b中下标为i的设置为true,
14                     // 代表不是素数,并且中断内层for循环,因为已经判断出i不是素数了,没有必要
15                     // 继续循环判断下去。 直接判断第i+1个数
16                     b[i] = true;
17                     break;
18                 }
19             }
20         }
21
22         /**
23          * 此部分内容在接下来将不写
24          */
25         int count = 0;
26         // 下标从2开始,是因为 1 不是素数也不是合数,没有必要判断
27         for (int i = 2; i <= n; i++) {
28             // 当为false时,代表素数
29             if (b[i] == false) {
30                 count++;
31             }
32         }
33     }

  注意:在第10行中的for循环内,使用的是 j * j <= i ,而不是 j <= sqrt(i)。原因:第一:sqrt是用来处理浮点数的,而浮点数的计算速度远远慢于integer。第二,函数调用也会造成时间的浪费。第三:浮点数的存储误差可能引出致命错误,如  sqrt(9)  可能等于 2.9999999 ,那么 int(sqrt(9)) 就等于2 而不是3。

阶段二

筛选法:在一张纸上写上 1-n 全部整数,然后逐个判断是否为素数,找出一个非素数,就把它挖掉,最后剩下的就是素数。

  具体做法如下:

  1. 先将 1 挖掉(因为1不是素数)
  2. 用 2 去除它后面的各个数,把能被 2 整除的数挖掉,即把 2 的倍数挖掉
  3. 用 3 去除它后面各数,把 3 的倍数挖掉
  4. 分别用 4、5 等数作为除数去除这些数以后的各数。这个过程一直进行到在除数后面的数已全被挖掉为止
  5. 剩下的数就是素数
 1 public void countPrime_2(int n) {
 2
 3         boolean[] b = new boolean[n + 1];
 4
 5         for (int p = 2; p * p <= n; p++) {
 6             // 假设当 p 为2时,也就是判断在数组 b 中下标为 2 的值是不是false,即 数字2 是不是素数
 7             // 如果是素数,就将 2 的倍数 4 6 8 10 等等全部标记为 非素数,即b[2] b[4] b[6] 的值为true
 8             if (b[p] == false) {
 9                 /**
10                  *  当 p 为 3 时,j = 3 * 3 = 9 。哎??? 怎么直接将 9 标记为 非素数了 ???
11                  *  不应该是将 6 先标记为 非素数吗? 直接标记 9 了,那 6 怎么办 ???
12                  *  因为: 6 也是 素数2的倍数,在计算素数 2 的时候就已经将6除去了
13                  *  所以直接从 p * p 开始计算,相当于又优化了
14                  *  j = j + p 代表跳到 p 的下一个倍数
15                  */
16                 for (int j = p * p; j <= n; j = j + p) {
17                     if (b[j] == false) {
18                         b[j] = true;
19                     }
20                 }
21             }
22         }
23     }

对于一个数p,会依次去除  p*p  ,  p*(p+1) , p*(p+2) .... p*(p+k)   【p*(p+k)<=n】

前面不是说要去除 p 的所有倍数的吗?那 p*2 ,p*3, p*4 ... p*(p-1)怎么不去除呢?

他们已经被去除了。因为当前我们要消去 p 的倍数,那么,之前一定去除了 2  3  4  ... p-3 , p-2 ,p-1  的这些数 的倍数,举个例子:之前一定去除了 2*p  3*p  4*p  (p-1)*p。所以 , 当想去除p的倍数时,如果我们还是去除 p*2  p*3  p*4  p*(p-1)  那么岂不是与 我们去除2的倍数时 会去除 2*p 、去除3的倍数时 会去除 3*p、去除4的倍数时 会去除 4*p  重复了 ???

原文地址:https://www.cnblogs.com/half-worm/p/8908414.html

时间: 2024-08-03 16:09:11

求 0-N 内有多少个素数的相关文章

SGU 231 Prime Sum 求&lt;=n内有多少对素数(a,b)使得a+b也为素数 规律题

题目链接:点击打开链接 题意: 求<=n内有多少对素数(a,b)使得a+b也为素数 思路: 我们发现所有素数间隔都是>=2的,且除了2都是奇数,那么: 奇数+奇数 = 偶数. 所以只有一种情况2+素数=素数. 所以打个素数表,看一下有多少个素数和前面那个素数间隔是2的. #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <

使用python求10万内的所有素数的个数

#求10万内的所有素数(9592) print(2) count = 1 for i in range(3,100000): for j in range(2,i): if i%j ==0: break if j==i-1: print(i) 优化: count = 1 for i in range(3,100000,2):#跳过所有偶数 for j in range(2,i): if i%j ==0: break if j==i-1: count +=1 print(count) 再优化: c

java求0~100的质数(素数)

质数的概念: 简单的来说就是一个数从2开始取模到(求余数)自身的值,如果取模后余数一直不等于0那么这个数就是质数(素数). 如 7     7%2    7%3    7%4    7%5   7%6  余数一直都不等于0    一直到7%7余数才为0:所以7是质数: 如 8   8%2余数直接为0:所以8不是质数: 如 9  9%2   9%3余数为0:所以8也不是质数: 下面直接上代码: package pkg1;//包名public class Test{//类名(注!该类名必须与文件名一

作业1:求500到1000之间有多少个素数,并打印出来

首先要知道什么是素数:所谓素数是指除了1和它本身以外,不能被任何整数整除的数. 数学里判断一个数n是否是素数,用n除以从2到这个数开方后所能取得最大整数,如果都不能整除,就说明这个数是素数. 所以这里我们用两层循环遍历 1 package com.etc; 2 public class IsSushu { 3 /** 4 * 第一题作业:求500到1000之间有多少个素数,并打印出来 5 * @param args 6 */ 7 public static void main(String[]

我的Java开发学习之旅------&gt;求N内所有的素数

一.素数的概念 质数(prime number)又称素数,有无限个.一个大于1的自然数,除了1和它本身外,不能被其他自然数(质数)整除,换句话说就是该数除了1和它本身以外不再有其他的因数:否则称为合数. 根据算术基本定理,每一个比1大的整数,要么本身是一个质数,要么可以写成一系列质数的乘积:而且如果不考虑这些质数在乘积中的顺序,那么写出来的形式是唯一的.最小的质数是2 二.算法 算法1. 开根号法:如果一个数(>2),对这个数求平方根,如果这个数能被这个数的平方根到2之间的任何一个(只要有一个就

埃氏筛法(求n以内有多少个素数)

题目大意:给定整数n,请问n以内有多少个素数 思路:想必要判断一个数是否是素数,大家都会了,并且可以在O(根号n)的复杂度求出答案,那么求n以内的素数呢,那样求就显得有点复杂了,下面看一下这里介绍的??氏算法 其实呢,就是求出第一个素数,然后把n以内它的倍数都删掉就行了,很简单.然后找下一个素数,同样方法····· 看代码 #include<iostream> #include<string.h> #include<map> #include<cstdio>

求N!中末尾有多少个0

分析: 对N进行质因数分解 N=2^x * 3^y * 5^z...,由于10 = 2*5,所以末尾0的个数只和x与z有关,每一对2和5相乘可以得到一个10,于是末尾0的个数=min(x,z).在实际中x是远远大于z的,所以我们只要求出z的值即可. 根据公式 z = N/5 + N/5^2 + N/5^3+...+N/5^k 这表明,5的倍数贡献了一个5,5^2的倍数又贡献了一个5.... 比如:25其实是贡献了2个5,但是在N/5中已经贡献了一个,所以在N/5^2中再贡献一个:同样,125在N

线性求欧拉函数值和筛选素数

2818: Gcd 题目: 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的 数对(x,y)有多少对. 1<=N<=10^7 算法: 求解 g = Gcd(x,y)为素数,转换问题成x/g,y/g互质.所以,只要求出[1,N/pi]内互质的对数(pi为1....N之间的素数).枚举pi就可以了.而这里就可以用到线性的欧拉求解,普通欧拉为O(nlognlogn). /* 线性素数加欧拉筛法O(N) 题目: 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数

C#筛法求出范围内的所有质数

    科普篇:筛法是一种简单检定素数的算法.据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274-194年)发明的,又称埃拉托斯特尼筛法(sieve of Eratosthenes). 说实话,之前我在求质数的场合都是验证某一数是否为质数的,用定义求即可方便的得出结论,代码如下: 01: public static bool IsPrime(int n) 02: {//判断n是否是质数 03: if (n < 2) return false; 04: for (int i =