质数筛法(判断是否为质数)

 

目录

朴素方法

埃氏筛法

欧拉筛法(线性筛)


质数又称素数,一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,也就是就是一个数除了1和它本身以外不再有其他的因数。若一个大于1的自然数,除了1和它本身外,还能被其他自然数整除,则该数成为合数。

注意:0,1既不是质数也不是合数。

朴素方法

因为质数除了1和本身之外没有其他因数,所以判断n是否为质数,只需判断从2到n-1是否存在数字能整除n即可

#include<iostream>
using namespace std;

bool isprime(int n)
{
	if (n < 2) return 0;//0,1不是质数

	for (int i = 2; i <= n - 1; i++)
	{
		if (n % i == 0)
		{
			return 0;//n与比它小的数相除,除的尽则不是质数

		}
	}
	return 1; //都除不尽,是质数
}

int main()
{
	int n;
	cin >> n;
	
	for (int i = 0; i < n; i++)
	{
		if (isprime(i))
		{
			printf("%d ", i);
		}
	}

	return 0;
}

以16为例 因数有

1                16

2                8

4                4

因为因数总是成对出现  所以只需要判断前面一列即可,也就是说isprime函数中的for循环只需循环到根号n即可

#include<iostream>
#include<cmath>
using namespace std;

bool isprime(int n)
{
	if (n < 2) return 0;//0,1不是质数

	//sqrt(n)用于求n的非负平方根  需要加头文件<cmath>
	int temp = sqrt(n);//判断到根号n

	for (int i = 2; i <= temp; i++)
	{
		if (n % i == 0)
		{
			return 0;//n与比它小的数相除,除的尽则不是质数

		}
	}
	return 1; //都除不尽,是质数
}


int main()
{
	int n;
	cin >> n;
	
	for (int i = 0; i < n; i++)
	{
		if (isprime(i))
		{
			printf("%d ", i);
		}
	}

	return 0;
}

埃氏筛法

小学老师曾经讲过:一个合数可以分解成若干个质数的乘积。我们由此可知,合数一定是质数的倍数,那么只要把质数的的倍数都去掉,那么剩下的就都是质数啦

求10以内的质数

1.假设arr[i]==1则i为质数        arr[i]==0则i不是质数        先假设都是质数  将数组arr全部置1        (因为0,1不是质数 所以这里数组下标直接从2开始)

下标2345678910
111111111

2.arr[2]=1,2是质数,把2的倍数置0

下标2345678910
110101010

3.arr[3]=1,3是质数,把3的倍数置0

下标2345678910
110101000

4.arr[4]=0,4是合数,跳过

下标2345678910
110101000

5.arr[5]=1,5是质数,把5的倍数置0

下标2345678910
110101000

......

9.arr[9]=0,9是合数,跳过

下标2345678910
110101000

10.arr[10]=0,10是合数,跳过

下标2345678910
110101000

全部循环完一遍啦        剩下值为1的数就是10以内的素数啦:2,3,5,7

埃氏筛法的过程大概就是这样啦,接下来上代码

#include<iostream>
using namespace std;

int prime[100005], k = 0;//prime数组用于存放素数
bool isPrime[100005];//isPrime[i]=1 则i是质数,	isPrime[i]=0 则i不是质数

int main()
{
	int n;
	cin >> n;
	
	//初始化 认为所有的数都是质数
	for (int i = 2; i <= n; i++)
	{
		isPrime[i] = 1;
	}

	//埃氏筛法
	for (int i = 2; i <= n; i++)
	{
		if (isPrime[i] == 1)//说明i是质数
		{
            k++;
			prime[k] = i;//将i放入prime数组
			for (int j = i * 2; j <= n; j += i)//从i的2倍开始枚举i的倍数(合数)
				isPrime[j] = 0;
			}
		}
	}

	for (int i = 1; i <= k; i++)
	{
		cout << prime[i] << " ";
	}
	return 0;
}

欧拉筛法(线性筛)

在埃氏筛法中,一个数可能被筛掉多次,比如在寻找10以内素数中,6被2,3筛掉2次;8被2,4筛掉2次...为了让每个数只被筛掉一次,就出现了欧拉筛法

欧拉筛法规定每个合数只会被它最小的质因数筛去,其他的质因数跳过。

比如:

18 = 2 * 3 * 3        则18只被3筛掉

110 = 2 * 5 * 11    110只被2筛掉

由此可得,i从2开始

i=2,2为素数,此时素数数组中有{2},被筛掉的数为2*2=4

i=3,3为素数,此时素数数组中有{2,3},被筛掉的数为2*3=6,3*3=9

i=4,4为合数,,此时素数数组中有{2,3},被筛掉的数为2*4=8(为什么此时不筛3*4=12呢?因为12的最小质因数为2,应在i=6时被2筛掉)

i=5,5为素数,此时素数数组中有{2,3,5},被筛掉的数为2*5=10,3*5=15,5*5=25

i=6,6为合数,此时素数数组中有{2,3,5},被筛掉的数为2*6=12

......

代码来啦~

#include<iostream>

using namespace std;

int prime[100005], k = 0;//prime数组用于存放素数
bool isPrime[100005];//isPrime[i]=1 则i是质数,	isPrime[i]=0 则i不是质数

int main()
{
	int n;
	cin >> n;
	
	//初始化 认为所有的数都是质数
	for (int i = 2; i <= n; i++)
	{
		isPrime[i] = 1;
	}

	//欧拉筛法
	for (int i = 2; i <= n; i++)//枚举需要判断的每个数 + 枚举倍数
	{
		if (isPrime[i] == 1)//次数为质数
		{
			k++;
			prime[k] = i;//将这个数放入质数数组中
		}

		//枚举质数表		质数表升序
		for (int j = 1; j <= k; j++)
		{
			int x = i * prime[j];//i为此时枚举判断的数  j从一开始遍历素数数组,因为不管这个数是素数还是合数都可先和质数数组中第一个元素2相乘筛掉一个值,所以直接把i与2相乘,结果保存在变量x中
			if (i * prime[j] > n)//超过要求的范围   跳出
			{
				break;
			}

			isPrime[x] = 0;//若没超过,把x标记成合数
			
			//保证每个合数被其最小质因数筛掉
			if (i % prime[j] == 0)
			{
                //保证了只筛选到以prime[j]为最小质因数的数
				break;
			}
		}
	}

	for (int i = 1; i <= k; i++)
	{
		cout << prime[i] << " ";
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值