第七周7.1数组运算课堂学习记录 求素数的方法改进/优化集锦《程序设计入门——C语言》第七期 浙江大学 翁恺

求素数基本方法及优化:

1.基本方法求素数:

从2到x-1测试是否可以整除,对于n来说要走n-1遍,n很大时相当于 遍。

#include<iostream>
using namespace std;

/*求素数基本方法*/
//从2到x-1测试是否可以整除,可以则非素数
//对于n来说要走n-1遍,n很大时相当于n遍
int isPrime(int x)	
{
	int ret = 1;
	int i;
	if (x == 1||x==0) { ret = 0; }
	for (i = 2; i < x ; i++)
	{
		if (x%i == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){

	int x;
	scanf("%d", &x);
	if (isPrime(x)) {
		printf("%d是素数\n", x);
	}
	else {
		printf("%d不是素数\n", x);
	}

	system("pause");
	return 0;
}

2.改进isPrime函数求素数:

去掉偶数(偶数一定不是素数)后,从3到x-1,每次加2。

如果x为偶数则立刻能判断,否则循环(n-3)/2遍,当n很大时相当于 n/2 遍。

完整程序(main函数未修改,只修改isPrime函数):

#include<iostream>
using namespace std;

/*求素数改进方法1:
去掉偶数(偶数一定不是素数)后,从3到x-1,每次加2。
如果x为偶数则立刻能判断
否则循环(n-3)/2遍
当n很大时相当于 n/2 遍*/
int isPrime(int x)		
{
	int ret = 1;
	int i;
	if (x == 1 || x == 0 || (x % 2 == 0 && x != 2)) {
		ret = 0; 
	}
	for (i = 3; i < x ; i+=2)
	{
		if (x%i == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){
	int x;
	scanf("%d", &x);
	if (isPrime(x)) {
		printf("%d是素数\n", x);
	}
	else {
		printf("%d不是素数\n", x);
	}
	system("pause");
	return 0;
}

3.进一步改进isPrime函数求素数:

去除偶数后从3遍历到√x即可。只需要循环约 √x/2 (sqrt(x)/2)

数学原理:从素数的定义来看,“一个大于1的自然数,如果除了1和它自身外,不能被其他自然数整除的数。”

          “因数”,我们要寻找的是除了自身与1没有因数的数字。而除了自身的平方根,因数都是成对存在的。而且这些因数对,一定是一大一小(除平方根外)。那么我们只要保留上面的遍历,但将遍历的终点设为所有因数对中较小值中的最大值(即平方根)就可以了。只要这个可以整除的值不存在,就说明该数字不存在因数对。那么自然也就是素数了。故而遍历只用到√x即可。

(注:原理转载自http://blog.sina.com.cn/s/blog_17b3f7fb60102x9wr.html

#include<iostream>
#include<math.h>
using namespace std;

/*求素数改进方法2
去除偶数后从3遍历到√x即可
只需要循环 √x (sqrt(x)) 遍
*/
int isPrime(int x)		
{
	int ret = 1;
	int i;
	if (x == 1 || x == 0 || (x % 2 == 0 && x != 2)) {
		ret = 0; 
	}
	for (i = 3; i <= sqrt(x) ; i+=2)
	{
		if (x%i == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){
	int x;
	scanf("%d", &x);
	if (isPrime(x)) {
		printf("%d是素数\n", x);
	}
	else {
		printf("%d不是素数\n", x);
	}
	system("pause");
	return 0;
}

4.求素数改进方法3:

判断是否能被已知的且<x的素数整除
只需要循环 比√x/2 更少的遍数——即 比x小的素数的个数

#include<iostream>
using namespace std;

/*求素数改进方法3
判断是否能被已知的且<x的素数整除
只需要循环 比√x/2 更少的遍数
*/

//输入已知素数表和要判断的数x,判断x是否能被已知的且<x的素数整除
int isPrime(int x , int knownPrimes[] , int number0fKnowPrimes)		
{
	int ret = 1;
	int i;
	for (i = 0 ; i < number0fKnowPrimes; i++)
	{
		if (x % knownPrimes[i] == 0) {
			ret = 0;
			break;
		}
	}
	return ret;
}

int main(){
	const int number = 7;	//输出前7个素数,可通过更改number改变想输出素数个数
	int prime[number] = { 2 };		//素数数组中第一个素数为2
	int count = 1;		//素数数组中素数的个数
	int i = 3;		//从3开始判断是否为素数

	/*调试用,输出表头
	{
		int i;
		printf("\t\t");
		for (i = 0; i < number; i++) {
			printf("%d\t", i);
		}
		printf("\n");
	}*/

	while (count < number) {
		//如果判断出i是素数的话,就把i加到prime数组中去
		if (isPrime(i, prime, count)) {					
			prime[count++] = i;		//此语句相当于:prime[count] = i;	count++;
		}
		/*调试用,方便输出查看变量变化
		{
			printf("i=%d \tcnt=%d\t", i, count);
			int i;
			for (i = 0; i < number; i++) {
				printf("%d\t", prime[i]);
			}
			printf("\n");
		}*/

		i++;
	}

	for (i = 0; i < number; i++) {
		printf("%d", prime[i]);
		if ((i + 1) % 10) printf("\t");
		else printf("\n");
	}

	system("pause");
	return 0;
}

加上调试查看素数prime数组(前7个)的结果:

不加调试输出前100个素数运行结果:

5.求素数改进方法终极版:构造素数表(和前面的方法思路相反)

构造m以内的素数表步骤:

(1)令x为2

(2)将2x,3x,4x……直至nx<m的标记为非素数(将素数的整数倍数字都标记为非素数)

(3)令x为下一个没有被标记为非素数的数字,重复步骤(2),直到所有的数字都已经尝试完毕,素数表即构造完成。

比如:现在有15以内的数字表:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

一开始全部标记为素数(红色),x = 2为素数,接着把2所有的倍数标记为非素数(黑色)之后变成:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

然后令让x为下一个素数,即 x = 3 ,继续把3所有的倍数标记为非素数之后变成:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

接着令让x为下一个素数,即 x = 5 ,继续把5所有的倍数标记为非素数之后变成:

2 3 4 5 6 7 8 9 10 11 12 13 14 15 

接着令让x为下一个素数,即 x = 7 ……,直到 x = 13 之后,不再有素数,就停止了,最后得到的红色的就是素数,得到了15以内相应的素数表:

2 3  5  7 11 13

伪代码:

代码:

#include<iostream>
using namespace std;

/* 求素数改进方法——构造素数表
将素数的整数倍数字都标记为非素数
遍历剩余素数指导全部标记完为止 */
int main(){
	const int maxNumber = 25;		//打印25以内的素数
	int isPrime[maxNumber];
	int i;
	int x;
	//初始化isPrime数组素数标志均为1
	for (i = 2; i < maxNumber; i++) {
		isPrime[i] = 1;
	}
	for (x = 2; x < maxNumber; x++) {
		//将素数的整数倍数字都标记为非素数
		if (isPrime[x]) {
			for (i = 2; i*x < maxNumber; i++) {
				isPrime[i*x] = 0;
			}
		}
	}

	//打印最终没有被标记为非素数的素数们
	for (i = 2; i < maxNumber; i++) {
		if (isPrime[i]) {
			printf("%d\t", i);
		}
	}
	printf("\n");
	system("pause");
	return 0;
}

输出结果:

测试查看算法标记非素数过程

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值