判断【素数】

质数

一、定义

质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数,也叫素数。

二、判断素数

给定一个数 n ,判断它是不是素数?

答:

可以使用循环,如果 这个数不能被 [ 2 , n − 1 ] [2,n-1] [2,n1] 内的所有数整除,那么它就是素数。

当然,这里 区间右侧只需要 到 n \sqrt{n} n 就可以,范围可以缩小到 [ 2 , n ] [2,\sqrt{n}] [2,n ]。这叫做使用 试除法判断素数

bool is_prime(int n){
    if(n<=1) return 0;         // 注意 1 不是素数。
    for(int i=2;i*i<=n;i++){    // 这里使用 i*i<=n 和 i<=sqrt(n) 是一样的。同时要带等号。
        if(n%i==0) return false;
    }
    return true;
}

这个函数中有一个循环,运行了 n \sqrt{n} n 次,时间复杂度为 n \sqrt{n} n

三、获得素数表

给定一个n ,需要获得比它小的所有素数。

答:

可以从 i = 2 i = 2 i=2 开始 ,循环到 i = n i = n i=n,依次判断 i i i 是不是素数。这样的话一个一个单独判断太慢了。

3.1 埃式筛法

埃式筛法从最小的素数2 开始,对于每一个素数,都掉该素数的倍数。

比如选出 10 以内的所有素数:

【1】2 是素数,那么筛掉所有 2 的倍数:

2 3 [4] 5 [6] 7 [8] 9 [10]

【2】3 没有被筛掉,得到 3 是素数,筛掉所有 3 的倍数:

2 3 [4] 5 [6] 7 [8] [9] [10]

【3】4 被筛掉了,4不是素数。

【4】5 没有被筛掉,得到 5 是素数,筛掉所有 5 的倍数:

2 3 [4] 5 [6] 7 [8] [9] [10]

【5】6 被筛掉了,6不是素数。

【6】7没有被筛掉,得到 7 是素数,筛掉所有 7 的倍数:

2 3 [4] 5 [6] 7 [8] [9] [10]

【7】8被筛掉了,8不是素数。

【8】9被筛掉了,9不是素数。

【9】10被筛掉了,10不是素数。

最终得到结果 2 , 3 , 5 , 7 {2,3,5,7} 2,3,5,7

可以发现 到 判断某个数 i i i ,是不是素数的时候,只要它没有被筛掉,那么它就是素数,这是为什么呢?因为如果这个数是不是素数,那么它一定有小于自己的 质数因子,而在这个数之前已经把小于该数的质数的倍数都筛掉了。

const int N = 1e7;		// 定义空间大小
int prime[N+1];			// 用来存放所有的素数
bool v[N+1]={0};         // 判断有没有被筛掉。
int find_prime(int n){
    int k=0; 						// 素数的个数
	for(int i=2;i<=n;i++){
        if(!v[i]){ 					// 如果 i 没有被筛掉
            prime[k++] = i;  			// 将 i 装到prime数组
        	for(int j=i+i;j<=n;j+=i)     // 将 i 的倍数筛掉
           		v[j] = true;
        }
   	}
    return k;			// 返回素数个数。
}

时间复杂度是 n l o g l o g n nloglogn nloglogn

3.2 优化埃式筛选法

上面的程序有两个地方可以优化:

【1】上面用来筛选的数,只需要到 n \sqrt{n} n 就可以了,比如筛选 100 以内的素数,需要用到 的素数为 2,3,5,7就够了。

【2】可以看到上面筛选 10 以内的素数的时候,10 被筛选了两次,也就是被重复筛选了,因为2筛选了一次,5也筛选了一次,当 i = 5 i=5 i=5的时候,2x5,3x5,4x5,都已经在前面 i = 2 , i = 3 , i = 4 i=2,i=3,i=4 i=2,i=3,i=4 的时候筛选了,也就是说筛选的时候可以从 i ∗ i i*i ii 开始。

const int N = 1e7;		// 定义空间大小
int prime[N+1];			// 用来存放所有的素数
bool v[N+1]={0};         // 判断有没有被筛掉。
int find_prime(int n){
	int k =0;
	for(int i=2;i*i<=n;i++){  // 开始筛选
		if(!v[i]){		// 如果 i 没有被筛选 
			for(int j=i*i;j<=n;j+=i) v[j] = true;  // 将 i 的倍数筛掉。
		}
	}
    
    for(int i=2;i<=n;i++){   // 遍历 2-n 将没有被筛选的数装到 素数表中
        if(!v[i]){
            prime[k++] = i;
        }
    }
    
    return k;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kwen-z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值