对筛质数三种方法的理解[普通筛,诶氏筛,线性筛]

//primes数组用来存放质数
int primes[N], cnt;

//i如果是质数则false,否则为true
bool st[N];

1.普通筛法 O(nlogn)
 

void get_primes(){
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) primes[cnt++] = i; //把素数存起来
        for(int j = i; j <= n; j += i)//不管是合数还是质数,都用来筛掉后面它的倍数
            st[j] = true;
    }
}


2.诶氏筛法 O(nloglogn)
 

void get_primes(){
    for(int i = 2; i <= n; i ++)
    {
        if(!st[i]){
            primes[cnt++] = i; //把素数存起来
            for(int j = i; j <= n; j += i)//仅用质数就可筛掉所有合数
                st[j] = true;
        }   
    }
}


3.线性筛法 O(n)

void get_primes(){
	for(int i = 2; i <= n; i ++)
	{
		if(!st[i]) primes[cnt++] = i;
		for(int j = 0; primes[j] <= n/i; j ++)
		{
			st[primes[j]*i] = true; //用最小质因子筛合数(已经挑出来的质因子的i倍)
			if(i % primes[j] == 0) break; // 此时primes[j]是i的i的最小质因子
		}
	}
}

        

if(i % primes[j] == 0) break;

对于👆的理解:

        对于一个数c=ab(b为c的最小质因数),当通过该算法的循环循环至cb时,易得此时c%b==0,如果此时继续循环至b后面的一个素数d,则有:cd=abd=(ad)b,因为d>b,所以ad>c。当循环从c继续查找到ad时我们发现当ad再次与素数b想乘时,就又对c*d进行了一次操作,出现了冗余,所以在if(n%prime[j]==0)成立时要将该层循环break掉;

        举个例子,对于一个数9,92=18将18标记为合数,循环继续;93=27将27标记为合数,此时发现9%3=0,循环退出。如果将循环继续下去会出现筛除95=45的情况,而45=153,在15时会被在筛去一次,故不可行

        

时间复杂度对比(s)

数据量10000000(10^7)

  • 普通筛:1.606
  • 埃及筛:0,316
  • 线性筛:0.098


数据量100000000(10^8)

  • 普通筛:28.134
  • 埃及筛:3.756
  • 线性筛:0.948
posted @ 2022-03-23 18:02  泥烟  阅读(35)  评论(0编辑  收藏  举报