目录
质数又称素数,一个大于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开始)
下标 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
值 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2.arr[2]=1,2是质数,把2的倍数置0
下标 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
值 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
3.arr[3]=1,3是质数,把3的倍数置0
下标 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
值 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
4.arr[4]=0,4是合数,跳过
下标 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
值 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
5.arr[5]=1,5是质数,把5的倍数置0
下标 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
值 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
......
9.arr[9]=0,9是合数,跳过
下标 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
值 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
10.arr[10]=0,10是合数,跳过
下标 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
值 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
全部循环完一遍啦 剩下值为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;
}