算法—素数的判断

算法—素数的判断

1.判断一个数是否为素数

bool judge01(int num)
{
	for (int i = 2; i <= sqrt(num); i++) {
		if (num % i == 0) {
			return false;
		}
	}
	return true;
}

2.筛法生成素数表

#include <iostream>
#include<math.h>
#define max 2000
using namespace std;
int num[2000] = { 0 };
int prime[1000] = { 0 };

int main()
{
	int i, j, k = 0;
	for (i = 2; i < max; i++) {//从i开始遍历
		if (!num[i]) {
			for (j = i + i; j < max; j += i) {//但凡是i的倍数全部剔除,将对应数组下标元素置为1
				num[j] = 1;
			}
			prime[++k] = i;//将i保存至素数表
		}
	}
	for (i = 0; i < k; i++) {//看用来记录素数表的大小
		cout << prime[i] << endl;
	}
	return 0;
}

3.六元素法

六素数,是相差为6的素数偶( p , p + 6 ),例如:
(5,11), (7,13), (11,17), (13,19), (17,23)…
由以上可以观察出,我们在求解素数的时候其实可以每次走的步数为6,这样和每次步长为一比起来可以大大节省时间


int prime02( int num )
{
	if(num <= 1)//
		return 0;
	if( num == 2 || num == 3 || num == 5 )
		return 1;
	if(num%2 == 0 || num%3 == 0 )	
		return 0;
	for(int i=5; i<=sqrt(num); i += 6 ){
		if( num % i == 0 || num % (i+2) == 0 )
			return 0;
	}
	return 1;
}

例题:

题目描述

有n盏灯,序号为1到n。在初始状态下,所有的开关都是关的。 有n个开关控制这n盏灯,第i个开关控制第i盏灯。
现在从1开始计数,每遇到一个素数就把该素数对应的倍数序号的开关朝相反的方向拨一下,一直到最后一个小于等于n的素数为止。请统计最后有多少盏灯是开的?

输入

多组输入,每组输入一个n(2<=n<=106)。

输出

每组数据,输出开的灯的盏数

**样例输入 **

10

样例输出

7

问题代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;
int light[1000000] = { 0 };

int prime(int num)//1.基本方法
{
	for (int i = 2; i <= sqrt(num); i++) {
		if (num%i == 0) {
			return 0;
		}
	}
	return 1;
}
int main()
{
	int n;
	while (scanf_s("%d", &n) != EOF) {
		memset(light, 0, sizeof(light));//置0函数不可缺
		//int light[1000000] = { 0 };//此时定义在主函数里面,当数组大小太大编译器会报错
		for (int i = 2; i <= n; i++){
			int Prime = prime(i);
			if (Prime) {
				//cout << i << endl;
				for (int j = 1; j*i <= n; j++) {
					if (light[j*i] != 1) {
						light[j*i] = 1;
					}
					else
						light[j*i] = 0;
				}
			}
		}
		int sum = 0;
		for (int i = 1; i <= n; i++) {
			if (light[i]) {
				sum++;
			}
		}
		cout << sum << endl;
	}
	return 0;
}

报错截图:
在这里插入图片描述

猜测原因是定义在函数里面,数据存放在栈区,申请内存过大超出编译器限值;当定义为全局变量是数据存放在全局区
较大的数组尽量定义在全局范围

问题分析: 即使如此还应和考虑问题的时限,就应该使用六素数法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;
int light[1000050] = { 0 };

int prime(int num)
{
	if (num < 2)return 0;
	if (num == 2 || num == 3 || num == 5)return 1;
	if (num % 2 == 0 || num % 3 == 0)return 0;
	for (int i = 5; i <= sqrt(num); i += 6) {
		if (num%i == 0 || num % (i + 2) == 0) {
			return 0;
		}
	}
	return 1;
}
int main()
{
	int n;
	while (scanf_s("%d", &n) != EOF) {
		memset(light, 0, sizeof(light));//置0函数不可缺
		for (int i = 2; i <= n; i++)
		{
			int Prime = prime(i);
			if (Prime) {
				//cout << i << endl;
				for (int j = 1; j*i <= n; j++) {
					if (light[j*i] != 1) {
						light[j*i] = 1;
					}
					else
						light[j*i] = 0;
				}
			}
		}
		int sum = 0;
		for (int i = 1; i <= n; i++) {
			if (light[i]) {
				sum++;
			}
		}
		cout << sum << endl;
	}
	return 0;
}

总结:
1.考虑数组的大小,较大时定义在全局范围
2.求素数优先考虑六素数法,高效
3.数组置0用memset()函数,不要忘记包含头文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

StarAndroid

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

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

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

打赏作者

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

抵扣说明:

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

余额充值