求素数的几种方法(暴搜法和筛选素数法)

参考自该篇博客https://www.cnblogs.com/grubbyskyer/p/3852421.html;

参考自该篇博客https://blog.csdn.net/liamleec/article/details/78524039

个人理解:

暴搜法:

其分为两种,一种是直接for循环,另一种是建立在数学思想上的平方根循环。第二种算法时间复杂度明显优于第一种。

1、暴力法:O(n*n)

也就是最简单直接的for循环,判定这个数是否能被除1 和其本身以外的整数整除。

2、sqrt(n)暴搜: O(n*sqrt(n))

这个也是基于for循环的一种方式,比上面那种方法稍微快了一点。当n的数值较大时,程序运行时间也比较长。原理:一个数只能被1和其本身整除,这样的数称为素数反之,不满足这个条件的即为非素数。
假定非素数num,一定能分解为两个整数的乘积,n和m,num = n * m;若n,m都大于sqrt(num),则不成立;所以,n和m中一定有一个小于等于sqrt(num)。换句话说,如果不存在这样的一个小于sqrt(num)的整数,则num就为素数。
代码:

#include<iostream>
#include<cmath>
using namespace std;
int main()
{
	int i,n, x;
	cin >> n;
	x = sqrt(n);
	for (i = 2; i <= x; i++)
		if (n % i == 0)
			break;               //跳出本层循环
	if (i > x)                   //找出小于sqrt(n)的整数
		cout << "Yes!";          //若无,则为素数,
	else
		cout << "No!";           //若存在,为非素数

	return 0;
}

筛选素数法:

1, 普通筛选法——埃拉托斯特尼(Eratosthenes)筛选法:O(n*loglogn)

要求n以内的素数,我们可以先构建一个大小为n+1的bool类型数组,并将各元素初始化为true(true表示为素数,false表示非素数),再通过算法将素数的下标所对应元素值赋为true,最后输出所有为true元素的下标即可。
用一个长度为n+1的数组保存信息(true表示素数,false表示非素数),先假设所有的数都是素数(初始化为true),从第一个素数2开始,把2的倍数都标记为非素数(置为false),一直到大于n;然后进行下一趟,找到2后面的下一个素数3,进行同样的处理,直到最后,数组中依然为true的数即为素数,遍历输出即可。

代码:

#include<iostream>
#include<algorithm>
#include<cstdbool>
using namespace std;
# define N 1024
int main()
{
	int tot = 0;
	bool num[N];
	memset(num, true, sizeof(num));       //初始化
	for (int i = 2; i < sqrt(N); i++)
	{
		if (num[i])
		{
			for (int j = 2; j * i < N; j ++)
			{
				num[j * i] = false;
			}
		}
	}

	for (int i = 2; i < N; i++)
	{
		if (num[i])
			cout << i << " ";
	}
	return 0;
}

2,二次筛选法:O(n*loglogn)

是普通筛选法算法的改进。

代码:

#include<iostream>
#include<algorithm>
#include<cstdbool>
using namespace std;
# define N 1024
int main()
{
	int tot = 0;
	bool num[N];
	memset(num, true, sizeof(num));       //初始化
	for (int i = 2; i < sqrt(N); i++)
	{
		if (num[i])
		{
			for (int j = i * i; j < N; j += i)
			{
				num[j] = false;      //二次筛选法:i是素数,则下一个起点是i*i,把后面的所有的i*i+2*n*i筛掉

			}
		}
	}

	for (int i = 2; i < N; i++)
	{
		if (num[i])
			cout << i << " ";
	}
	return 0;
}

3,线性筛选法:O(n)

在普通筛选法的基础之上进行最大程度的优化。普通筛选法在提高运行效率的同时也有缺点,就是很多数被处理了不止1遍,因此又造成了比较大的不必要处理。比如说非素数6,以2进行筛选时筛选了一次,以3进行筛选,又筛选了一次,线性筛选素数就是一个非素数以最小质因数筛选一次即可。

代码:

#include<iostream>
#include<algorithm>
#include<cstdbool>
using namespace std;
# define N 1024
int main()
{
	int tot = 0;
	bool num[N];                           //判定是否为素数
	int prime[N];                          //素数集合
	memset(num, true, sizeof(num));        //初始化
	for (int i = 2; i < N; i++)
	{
		if (num[i])
			prime[tot++] = i;
		for (int j = 0; j < tot && prime[j] * i < N; j++)
		{
			num[prime[j] * i] = false;
			if (i % prime[j] == 0)         
				break;
		}
	}

	for (int i = 2; i < N; i++)
	{
		if (num[i])
			cout << i << " ";
	}
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值