质数判断|质数筛法

  • Post author:
  • Post category:其他




质数



概述


质数

(prime number,又称素数):

指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个

正因数

的数)。

否则称为

合数

(又称合成数)。






1既不是质数也不是合数,2是最小的质数且是唯一的偶质数



质数判断



试除法



O

(

n

)

O(\sqrt{n})






O


(










n
























)






思想

:根据定义,可以从2~n-1依次试除,判断n是否有约数(若有则n不是质数)


优化

:假设



d

d






d





可以整除



n

n






n





,那么它们的商



n

/

d

n/d






n


/


d





也能整除



n

n






n





。假设两者的关系是



d

<

=

n

/

d

d<=n/d






d




<=








n


/


d





,即



d

2

<

=

n

d^2<=n







d










2











<=








n





,那么



d

<

=

n

d<=\sqrt n






d




<=















n


























。所以每次判断只需要判断到



n

\sqrt{n}














n



























即可。


时间复杂度

:优化后时间复杂度为



O

(

n

)

O(\sqrt{n})






O


(










n
























)




bool isprime(int n) 
{
	for (int i = 2; i <= n / i; i++)//也有的会写为i*i<=n,不过存在溢出风险,使其变为负数,影响结果判断。最好写为i<=n/i,不存在溢出风险
		if (n % i == 0) return false;
	return true;
}



质数筛法



朴素筛法



O

(

n

n

)

O(n\sqrt{n})






O


(


n










n
























)






背景

:质数相关的问题,如果用传统的遍历法的话,一次只能求解一个(



O

(

n

)

O(\sqrt n)






O


(









n























)






过程:

试除法将素数保存下来即可

int prime[N], cnt;
for (int i = 2; i <= 100; i++)
    if (isprime(i))prime[++cnt] = i;


埃氏筛法



O

(

n

l

o

g

n

)

O(nlogn)






O


(


n


l


o


g


n


)






思想

:从2开始任何整数 x 的倍数都不是质数。


过程

:初始时,先假设所有数都是质数,从2开始枚举,并标记每个数的倍数为合数,若枚举到一个数未被标记,说明该数就是质数。


时间复杂度





O

(

n

l

o

g

n

)

O(nlogn)






O


(


n


l


o


g


n


)




int prime[N], cnt;
bool st[N];
void GetPrimes(int n) 
{
    memset(st, true, sizeof(st));
    for (int i = 2; i <= n; i++) 
    {
        if (st[i]) prime[++cnt] = i;
        for (int j = i + i; j <= n; j += i) st[j] = false;//筛掉该数的倍数
    }
}


埃氏筛相关

1、埃拉托斯特尼选筛法,简称埃氏筛,也有人称素数筛。

2、

算术基本定理

(又称唯一分解定理),任何一个大于1的自然数N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积。也就是说,合数一定是某个质数的倍数。


优化

:埃氏筛法是不管是合数还是质数都直接筛,会有许多重复的操作。根据算术基本定理,只筛掉质数的倍数。


时间复杂度





O

(

n

l

o

g

l

o

g

n

)

O(nloglogn)






O


(


n


l


o


g


l


o


g


n


)





该算法实现简单,效率已经非常接近与线性(n <= 10

6

int prime[N], cnt;
bool st[N];
void GetPrimes(int n) 
{
    memset(st, true, sizeof(st));
    for (int i = 2; i <= n; i++)
    {
        if (!st[i])continue;//合数
        prime[++cnt] = i;
        for (int j = i + i; j <= n; j += i) st[j] = false;//筛掉质数倍数
        //遍历范围内的i的倍数 可从i*i开始,可以减少重复筛选(
    }
}


线性筛法



O

(

n

)

O(n)






O


(


n


)





欧拉筛,也被称作线性筛


背景

:埃氏筛中一些合数被重复筛选(如:6会被2和3筛选),这样会有许多重复操作


思想

:在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的


时间复杂度





O

(

n

)

O(n)






O


(


n


)





当数据规模在

10

6


时,线性筛法和埃式筛法效率差不多,但是当数据规模在

10

7


时线性筛法的效率大约是埃式筛法

2倍

int prime[N], cnt;
bool st[N];
void GetPrimes(int n)
{
	memset(st, true, sizeof(st));
	for (int i = 2; i <= n; i++)
	{
		if (st[i])prime[++cnt] = i;
		for (int j = 1; prime[j] <= n / i; j++)
		{
			st[prime[j] * i] = false;
			//(prime[j] * i)为要筛掉的合数
			//(prime[j] * i)的最小质因数 = min(prime[j]的最小质因数, i的最小质因数)
			//质数prime[j]的最小质因数是它本身
			//当i% prime[j] != 0时,i的最小质因数>prime[j],所以(prime[j] * i)的最小质因数 = prime[j]
			//当i% prime[j] == 0时,i的最小质因数=prime[j],所以(prime[j] * i)的最小质因数 = prime[j]
			if (i % prime[j] == 0)break;
			//若i% prime[j] == 0后继续枚举质数表,那么prime[j+1]>prime[j],即prime[j+1]不是i的最小质因子
			//自然prime[j+1]不是(prime[j]*i)的最小质因子
		}
	}
}



版权声明:本文为m0_51456060原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。