定义及性质
质数又称为素数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
只有两个正因数(1和自己)的自然数即为质数。比1大但不是素数的数称为合数。1和0既非素数也非合数。
所有大于1的正整数都可以表示成素数的和。所有的合数都可以写成一个素数乘以一个自然数的形式,这个素数被称为该合数的素因子。
判断一个数是否为素数
- 一个合数除它本身以外的最公约数小于等于它的平方根
/*************************************************************************
> File Name: 2.is_prime_1.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年04月16日 星期五 09时57分33秒
> 判断一个数是否是素数 时间复杂度 O(n^(1/2))
************************************************************************/
#include<stdio.h>
#include<math.h>
int is_prime(int x) {
if(x < 2) return 0;
for(int i = 2; i <= sqrt(x); i++) {
if(x % i == 0) return 0;
}
return 1;
}
int main() {
int n;
scanf("%d", &n);
printf("%s\n", is_prime(n) ? "Yes" : "No");
return 0;
}
- 大于2的偶数都不是素数
/*************************************************************************
> File Name: 2.is_prime_2.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年04月16日 星期五 09时57分33秒
> 判断一个数是否是素数 时间复杂度 O((n^(1/2))/2)
************************************************************************/
#include<stdio.h>
#include<math.h>
int is_prime(int x) {
if(x == 2) return 1;
if(x < 2 || x % 2 == 0) return 0;
for(int i = 3; i <= sqrt(x); i += 2) {
if(x % i == 0) return 0;
}
return 1;
}
int main() {
int n;
scanf("%d", &n);
printf("%s\n", is_prime(n) ? "Yes" : "No");
return 0;
}
- 大于2素数均在6的倍数两侧
/*************************************************************************
> File Name: 2.is_prime_3.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年04月16日 星期五 10时10分07秒
> 判断一个数是否是素数 时间复杂度 O((n^(1/2))/6)
************************************************************************/
#include<stdio.h>
#include<math.h>
int is_prime(int x) {
if(x == 2 || x == 3) return 1;
if(x % 6 != 1 && x % 6 !=5 ) return 0;
for(int i = 5; i <= sqrt(x); i += 6) {
if(x % i == 0 || x % (i + 2) == 0) return 0;
}
return 1;
}
int main() {
int n;
scanf("%d", &n);
printf("%s\n", is_prime(n) ? "Yes":"No");
return 0;
}
素数筛
用素数来枚举合数,所有的合数都可以可写成:一个素数乘以一个大于1自然数。
/*************************************************************************
> File Name: 2.is_prime_4.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年04月16日 星期五 10时30分58秒
> 素数筛:判断10000内的一个大于1的自然数是否是素数 O(n*log n);
************************************************************************/
#include<stdio.h>
#define MAX_N 10000
int prime[MAX_N + 5];
// 构造函数,优先于main函数执行
__attribute__((constructor))
void init_prime() {
for(int i = 2; i <= MAX_N; i++) {
if(prime[i]) continue; // i是合数
for(int j = i; j < MAX_N / i; j++) {
prime[i * j] = 1; // 素数乘以一个大于本身的自然数为合数
}
}
}
int main() {
int n;
while(~scanf("%d", &n)) {
if(n < 2 || n > 10000) break;
printf("%s\n", prime[n] ? "No" : "Yes");
}
return 0;
}
素数筛扩展
- 输出n(n < 10000)以内的所有素数
/*************************************************************************
> File Name: 2.is_prime_4_ex.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年04月16日 星期五 10时44分30秒
> 用素数筛来枚举n以内的所有素数
************************************************************************/
#include<stdio.h>
int n;
int prime[10005];
void init_prime() {
for(int i = 2; i <= n; i++) {
if(prime[i]) continue;
prime[++prime[0]] = i; // i为素数,存储到已检测过的区域
for(int j = i; j <= n / i; j++) {
prime[i * j] = 1;
}
}
}
int main() {
scanf("%d", &n);
if(n < 2 || n > 10000) return 0;
init_prime();
for(int i = 1; i <= prime[0]; i++) {
printf("%d\n", prime[i]);
}
return 0;
}
- N以内所有数字的最大/最小素因子
/*************************************************************************
> File Name: 2.min_prime_factory.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年04月16日 星期五 10时56分38秒
> 求一个数字的最小素因子
************************************************************************/
#include<stdio.h>
#define MAX_N 10000
int prime[MAX_N + 5];
__attribute__((constructor))
void prime_init() {
for(int i = 2; i <= MAX_N; i++) {
if(prime[i]) continue;
for(int j = i; j <= MAX_N; j+= i) {
if(prime[j]) continue; // 求最大素因子,去掉此行就可以
prime[j] = i;
}
}
}
int main() {
int n;
while(~scanf("%d", &n)) {
if(n < 2 || n > MAX_N) break;
printf("min_prime_factory[%d] = %d\n", n, prime[n]);
}
return 0;
}
线性筛
用素数来枚举合数,所有的合数都可以写成,一个素数乘以一个大于1自然数。线性筛是对素数筛的一个改进,通过统计素数进一步缩小了内部循环的次数。内部进行范围判断和赋值判断跳出循环,使得线性筛的时间复杂度接近O(n)
。
/*************************************************************************
> File Name: 2.prime_list.c
> Author: 陈杰
> Mail: 15193162746@163.com
> Created Time: 2021年04月16日 星期五 11时28分06秒
> 线性筛枚举n以内的所有素数
************************************************************************/
#include<stdio.h>
int prime[10005];
void init_prime(int n) {
for(int i = 2; i <= n; i++) {
// 将素数存储到已检测过的区域
if(!prime[i]) prime[++prime[0]] = i;
// 枚举i以内的素数
for(int j = 1; j <= prime[0]; j++) {
// 超出数据范围退出循环
if(prime[j] * i > n) break;
prime[prime[j] * i] = 1;
// 已经找到i的最小素因子,退出循环(防止重复标记)
if(i%prime[j] == 0) break;
}
}
}
int main() {
int n;
scanf("%d", &n);
if(n < 2 || n > 10000) return 0;
init_prime(n);
for(int i = 1; i <= prime[0]; i++){
printf("%d\n", prime[i]);
}
return 0;
}