求素数个数(三种判断素数方法

文章探讨了求解1到n之间素数个数的不同算法,包括暴力法、开根号法、埃氏筛法和欧氏筛法,并分析了它们的效率和执行时间,强调了设计高效算法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

description

求素数的个数。本题要求编写一个程序,求1~n的素数个数。 要求至少给出两种解法,对于相同的n,给出这两种解法的结果,通过相关数据进行测试,目的是通过对比同一问题不同解法的绝对执行时间体会如何设计“好”的算法。

输入格式:

输入在一行中给出1个整数n(<= 10 000 000)。

输出格式:

对每一组输入,在一行中输出1~n的素数个数。

输入样例1:

5

输出样例1:

3

输入样例2:

14

输出样例2:

6

solution

暴力法

传统方法,从2到n-1依次试,4,5,6测试点超时

#include <stdio.h>
int main(){
	int n, count = 0, flag;
	scanf("%d", &n);
	for(int i = 2; i <= n; i++){
		flag = 1;
		for(int j = 2; j < i; j++){
			if(i%j == 0){
				flag = 0;
				break;
			}
		}
		count += flag;
	}
	printf("%d", count);
	return 0;
}

开根号法:从2到sqrt(n)均整除判断(原因:素数是因子为1和本身, 如果数c不是素数,则还有其他因子,其中的因子,假如为a,b.其中必有一个大于sqrt© ,一个小于sqrt© 。所以m必有一个小于或等于其平方根的因数,故只验证到其方根即可),5,6测试点依然超时

#include <stdio.h>
#include <math.h>
int main(){
	int n, count = 0, flag;
	scanf("%d", &n);
	for(int i = 2; i <= n; i++){
		flag = 1;
		for(int j = 2; j <= i / j; j++){
		//判断条件j <= sqrt(i)每次计算较麻烦,不推荐
		//j * j <= i有溢出风险,不推荐
			if(i%j == 0){
				flag = 0;
				break;
			}
		}
		count += flag;
	}
	printf("%d", count);
	return 0;
}

埃氏筛法(朴素筛法)

  • 空间换时间
  • 因为一个合数一定能被分解为几个质数的幂的乘积,并且这个数的质因子一定是小于它本身的,所以当我们从小到大将每个质数的倍数都筛去的话,当遍历到一个合数时,它一定已经被它的质因子给筛去了。
    但是6测试点超时……
#include <stdio.h>
int hash[10000010] = {0};//初始为全是素数 
int main(){
	int n, count = 0;
	scanf("%d", &n);
	for(int i = 2; i <= n; i++){
		if(!hash[i]){
			count++;
			for(int j = 2 * i; j <= n; j += i)
				hash[j] = 1;
		}
	}
	printf("%d", count);
	return 0;
}

进一步优化,2 * 3我们已经判断过了,就没有必要再判断3 * 2了,因此从i*i开始判断即可
然鹅有时通过,有时测试点6超时……

#include <stdio.h>
const int N = 1e7 + 10;
int hash[N] = {0};//初始为全是素数 
int main(){
	long long n, count = 0;
	scanf("%lld", &n);
	for(long long i = 2; i <= n; i++){
		if(!hash[i]){
			count++;
			for(long long j = i * i; j <= n; j += i)
				hash[j] = 1;
		}
	}
	printf("%lld", count);
	return 0;
}

欧氏筛法(线性筛法)

#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int prime[N], cnt;//prime存储质数,cnt是当前已有的质数个数 
bool st[N];//是否被筛选掉,即是否为质数 
int main(){
	int n;
	scanf("%d", &n);
	for(int i = 2; i <= n; i++){
		if(!st[i]) prime[cnt++] = i;//还没有被筛掉,则为质数
		for(int j = 0; prime[j] <= n / i; j++){//确保 primes[j] * i 不超过 n,避免越界
			st[prime[j] * i] = true;//标记 primes[j] * i 为合数
			if(i % prime[j] == 0) break; //剪掉重复筛选的过程,实现线性( i 能被 primes[j] 整除,说明 i 的最小质因数是 primes[j]
		} 
	} 
	printf("%d", cnt);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值