线性筛选素数

线性筛选素数

问题

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

方法一

方法一概述

使用数字prime[i]来标记i是否为素数。初始化prime[2…n]=1。
当处理到数字i时,若prime[i]=0,则代表2到i-1中有i的因子,因此i为合数;若prime[i]=1,则代表2到i-1中无i的因子,因此i为素数,此时筛选掉ij(2<=j<=n/i),从而筛选掉以素数i为因子的合数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,会在i为2和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_ipi<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]来进行筛选,并通过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]为最小素因子的合数都会被筛选掉。
操作过程示例:
线性筛选素数_第1张图片

方法二实现

#include
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();
}

你可能感兴趣的:(算法)