[题解]谭浩强C语言(第三版)习题7.1 用筛法求素数

题目

题目描述

用筛法求之N内的素数。

输入描述

N

输出描述

0~N的素数

样例输入

100

样例输出

2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97


题解

分析

题目要求用筛法求素数。
什么筛法呢?

  1. 先假定从2开始逐次递增的一组数全部为素数,
  2. 从小到大逐个取出(假设取出的数为x),则x除了它本身以外的全部倍数均不是素数,将x的倍数从这组数筛除。




例如:
起始的数为2~100

  1. 假设这组数全部为素数
  2. 取出第一个数2
  3. 2除了本身以外的倍数均不是素数,如4,6,8,10,12等。将这些数筛除。
  4. 以此类推,取出第二个数,重复筛除倍数的操作。

假设取出的数为x。

当x = 2时,x为素数。
当x > 2时,因为x不能被 2~x-1中的数整除,所以x也为素数。
因此取出的数x必为素数

代码参考(基础版)
#include<stdio.h>
#define MAX 100000
#define NIL -1  //筛除标志
int a[MAX];
int main()
{
	int n,i,j;
	scanf("%d",&n);
	for(i = 0;i <= n;i++)
		a[i] = i;       //初始化数组
	a[0] = a[1] = NIL;  //删除0和1
	for(i = 2;i <= n;i++)
	{
		if(a[i] != NIL)
		{
			for(j = a[i] * 2;a[j] <= n;j += i)
				a[j] = NIL;
		}
	}
	for(i = 0;i <= n;i++)
		if(a[i] != NIL)
			printf("%d\n",a[i]);
	return 0;
}
代码分析

该代码利用了筛法的最基本思路实现。适合初学者参考。

但在速度和空间利用率上,可以被进一步优化,请看进阶版代码。

代码参考(进阶版)
#include<cstdio>
#include<vector>
using namespace std;
int main()
{
	int n;
	vector<bool> a;
    scanf("%d",&n);
	a.resize(n + 1);	//初始化时默认值为false。我们设值false表示未被筛除,true表示被筛除。下标为对应的数
	a[1] = a[0] = true;		//将0和1筛除
	for(int i = 0;i <= n;i++)
	{
		if(!a[i])
		{
			printf("%d\n",i);
			for(int j = i + i;j <= n;j += i)
				a[j] = true;
		}
	}
	return 0;
}
代码分析
  • 借助C++的vector类进行实现,存储空间可以根据数据规模而改变,大大提升了数据的空间利用率。
  • 并且不再将数本身直接存储在数组中,而是用bool类型的标志变量。相比于使用int的变量,进一步较小的空间的消耗。
  • 计算速度方面,由于vector默认初始变量值为false,所以无需再使用for循环进行初始化。相比于基础版,免去了一个线性时间消耗。
  • 因为for循环每次取出的未被筛除的数都是素数,所以可以把结果输出与筛法算法执行过程结合,再次减小了一个线性时间消耗。

题解为本人原创。
如有疏漏欢迎指正。
欢迎在评论区和我共同探讨、学习交流呀。
原创不易,转载请说明出处。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wingaso

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值