线性筛选素数

线性筛选素数

问题

求取范围 [ 2 , n ] [2,n] [2,n] 之间的所有素数

方法一

方法一概述

使用数字 p r i m e [ i ] prime[i] prime[i]来标记 i i i是否为素数。初始化 p r i m e [ 2... n ] = 1 prime[2...n]=1 prime[2...n]=1
当处理到数字 i i i时,若 p r i m e [ i ] = 0 prime[i]=0 prime[i]=0,则代表 2 2 2 i − 1 i-1 i1中有 i i i的因子,因此 i i i为合数;若 p r i m e [ i ] = 1 prime[i]=1 prime[i]=1,则代表 2 2 2 i − 1 i-1 i1中无 i i i的因子,因此 i i i为素数,此时筛选掉 i ∗ j ( 2 < = j < = n / i ) i*j(2<=j<=n/i) ij(2<=j<=n/i),从而筛选掉以素数 i i i为因子的合数 i ∗ j i*j ij

方法一实现

#define SIZE 1000000

int main()
{
    int check[SIZE] = {0};//元素值为0代表是素数
    int prime[SIZE] = {0};
    int pos=0;
    int flag;
    for (int i = 2 ; i < SIZE ; i++)
    {
        if (!check[i])//如果是素数
            prime[pos++] = i;

        for (int j = 2*i ; j < SIZE ; j += i)
        {
            check[j] = 1;
        }
    }
    printf("%.2f", (double)clock()/CLOCKS_PER_SEC);

    return 0;
}

方法一问题

时间复杂度为 O ( n 2 ) O(n^2) O(n2),存在重复筛选的问题。对于 6 = 2 ∗ 3 6=2*3 6=23,会在 i i i 2 2 2 3 3 3时被筛选掉。

方法二——线性筛法

方法二概述

目标:对于 m = p i a ∗ p j b ∗ . . . p k c m=p_i^{a}*p_j^{b}*...p_k^{c} m=piapjb...pkc,其中 p i < p j < . . . p k p_i<p_j<...p_k pi<pj<...pk,为了避免重复筛选,仅使用 p i p_i pi来筛选数 m m m,称 p i p_i pi为最小素因子。
策略:
使用prime数组来记录当前所得到的素数,使用is_prime[i]来标记数i是否被筛选。
对于当前数m,若其没有被筛选,则将其加入prime数组中。无论m是否为素数,遍历prime数组,来筛选掉以 p r i m e [ i ] prime[i] prime[i]为最小素因子且等于 m ∗ p r i m e [ i ] m*prime[i] mprime[i]的合数,为了确保 m ∗ p r i m e [ i ] m*prime[i] mprime[i]是以prime[i]为最小合数的,因此若出现 p r i m e [ i ] ∣ m prime[i]|m prime[i]m(即m中含有素因子 p r i m e [ i ] prime[i] prime[i]),将不在考虑使用 m ∗ p r i m e [ j ] ( j > i ) m*prime[j](j>i) mprime[j](j>i)来进行后续的筛选(因为此时的最小素因子为m的最小素因子 p r i m e [ i ] prime[i] prime[i]而非 p r i m e [ j ] prime[j] prime[j])。
覆盖性证明:
上述策略保证了使用最小素因子 p r i m e [ i ] prime[i] prime[i]来进行筛选,并通过 p r i m e [ i ] ∣ m prime[i]|m prime[i]m来避免了重复的筛选,即满足了一个数仅筛选一次的目标。
对于筛选的范围能否覆盖 [ 1... n ] [1...n] [1...n]中的所有数,由于m是从1到n遍历的,因此会考虑到所有 m ∗ p r i m e [ i ] ( m = 1... n ) m*prime[i](m=1...n) mprime[i](m=1...n)的情况(当 p r i m e [ i ] > m m i n prime[i]>m_{min} prime[i]>mmin时不予筛选, m m i n m_{min} mmin代表m的最小素因子,因为这不满足 p r i m e [ i ] prime[i] prime[i] m ∗ p r i m e [ i ] m*prime[i] mprime[i]为最小素因子的定义),因此所有以prime[i]为最小素因子的合数都会被筛选掉。
操作过程示例:
在这里插入图片描述

方法二实现

#include<iostream>
using namespace std;
#define NUM 20
void get_prime() {
	int is_prime[NUM] = { 0 };
	int prime[NUM];
	int prime_num = 0;
	for (int m = 2; m < NUM; m++) {
		//数m没有被筛选过
		if (!is_prime[m]) {
			prime[prime_num++] = m;
		}
		//筛选掉以prime[i]为最小素因子的合数m*prime[i]
		for (int i = 0; i < prime_num; i++) {
			if(m*prime[i]<NUM) is_prime[m * prime[i]] = 1;
			if (m % prime[i] == 0) break;//m*prime[j](j>i)的最小素因子为m的最小素因子prime[i]而非prime[j],因此跳出循环
		}
	}
	//打印输出
	for (int i = 0; i < prime_num; i++) {
		cout << prime[i] << " ";
	}
	cout << endl;
}
int main() {
	get_prime();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值