判断素数, 根据数据量大小, 可以分为普通方法, 埃氏筛法, 欧拉筛法; 其中 埃氏筛法and欧拉筛法是找到比 N 小的所有素数, 从效率上来说, 欧拉优于埃氏;
1. 普通法
#include <bits/stdc++.h>
using namespace std;
int main (){
int n;
cin >> n;
for (int i = 2; i * i <= n; i ++){
if (n % i == 0){
cout << "不是素数";
return 0;
}
}
cout << "是素数";
return 0;
}
简单粗暴, 从2开始取余一直到 i == 根号n, 如果有能被整除的情况就不是素数, 适合判断单个数据。
2, 埃氏
#include <bits/stdc++.h>
using namespace std;
int main()
{ int n;
cin >> n;
bool flag [n + 1];
memset (flag, 1, sizeof (flag) / sizeof (flag[0]));
flag [0] = flag[1] = 0;
int prime[n + 1] = {0};
for (int i = 2; i <= n; i ++){
if (flag [i] == 1){
for (int j = 2; i * j <= n; j ++){
flag[i * j] = 0;
}
}
}
int count = 0;
for (int i = 2; i <= n; i ++){
if (flag[i] == 1){
cout << i << "是素数" << " ";
count ++;
}
}
cout << count << "个" << endl;
return 0;
}
埃氏筛法:就是找小于等于n的所有素数, 我们定义一个bool类型数组flag,flag[ i ] 代表 i 是不是素数, 是为1 不是为0, 初始值全部为1, flag[ 0 ], flag[ 1 ]例外 他俩不是素数,so 让他俩等于0,for循环 遍历从2到n的所有数 挨个判断, 如果i是素数,即flag[ i ] == 1, 该素数的倍数应当全部删掉, 并且删掉的倍数一定要小于等于n。
埃氏筛有个小小问题, 那就是重复的删除, 比如 2 是素数,2会将4,6,删掉, 3也是素数, 3也会将6删掉, 一个6被2, 3 删除两次,造成时间上的浪费, 欧拉筛会解决这个问题;
3. 欧拉筛
欧拉筛法, 是埃氏筛的改进版, 一个素数只删一个合数, 相当优秀, 当然还有比它优秀的, but我不会, 以后我会学会的,
#include <bits/stdc++.h>
using namespace std;
void judge_prime(int n){
bool flag [n + 1];
int count = 0;
int prime [n + 1];
memset (flag , 1 , sizeof (flag)/sizeof (flag [0]));
for (int i = 2;i <= n;i ++){
if (flag [i]){
prime [++ count] = i;
}
for (int j = 1;i * prime [j] <= n;j++){
flag [i * prime [j]] = 0;
if (i % prime [j] == 0){
break;
}
}
}
for (int i = 1;i <= count;i ++){
cout << prime [i] << endl;
}
cout << setprecision (20) << count << "个" << endl;
}
int main()
{ int N;
cin >> N;
judge_prime(N);
return 0;
}
几乎所有的地方都跟埃氏一样, 就一个地方不同, 多了一个i % prime [ i ] == 0, 这句话是精髓,i % prime[ i ] == 0;代表这个i 被prime[i] 曾经删除过; 比如,i * prime[i] = 0; 之后 i * prime[i] 变成了 新的 i 这个新的 i 先进行i * prime[i] = 0; 然后 if (i % prime[i] == 0) 相当于,
(i * prime[i]) % prime[i] 这肯定等于零,也就完成了一个合数只被删一次的任务;