MOOC-eg-素数判断及构造素数表

本文总结归纳于翁恺老师MOOC的相关内容。

关于素数可能有许多不同的题目要求,例如输入数据单纯的进行素数判断,又或者进行给定范围内的素数加和,又或者要求制作素数表,等等。因此可以考虑将素数判断单独写为函数,在实现不同要求的时候直接进行调用。本文首先介绍素数判断的基础方法及其简化方法,随后针对构造素数表的要求给出了具体代码。

一、素数判断函数

1.最基础的:利用2到x-1是否能被输入整除进行判断

/**
利用2到x-1是否能被输入整除进行判断 
@param x   待判断是否为素数的正数
*/ 
int isPrime(int x)
{
	int i;
	int ret = 1; //素数:1   非素数:0
	if( x==1 ) ret = 0;  // 1不是素数 
	for( i = 2 ; i<x ; i++ ){
		if( x%i==0 ){
			ret = 0;
			break;
		}
	} 
	return ret;
 } 

2.优化(减少循环次数):除2外的偶数均非素数,故可去除偶数后从3开始遍历至x-1,每次加2,无整除则为素数

/**
除2外的偶数均非素数,故去除偶数后,从3到x-1,每次+2 ,遍历是否能被输入整除进行判断 
@param x   待判断是否为素数的正数
*/ 
int isPrime(int x)
{
	int i;
	int ret = 1; //素数:1   非素数:0
	if( x==1 || ( x%2==0 && x!=2 )) ret = 0;  // 1不是素数 
	for( i = 3 ; i<x ; i+=2 ){
		if( x%i==0 ){
			ret = 0;
			break;
		}
	} 
	return ret;
 } 

3.进一步优化:非素数一定能整除不超过其平方根的某个正数

  /**
非素数一定能够整除一个不超过其平方根的整数(因式分解) 
@param x   待判断是否为素数的正数
*/ 
int isPrime(int x)
{
	int i;
	int ret = 1; //素数:1   非素数:0
	if( x==1 || ( x%2==0 && x!=2 )) ret = 0;  // 1不是素数 
	for( i = 3 ; i<=sqrt(x) ; i+=2 ){
		if( x%i==0 ){
			ret = 0;
			break;
		}
	} 
	return ret;
 } 

4. 另一种方案:判断能否被已知的且小于x的素数所整除,若不能,则x为素数

该方法也需要进行遍历,但遍历的是小于x的素数,故需要知晓小于输入的素数表,考虑到最终要求是构造素数表,这种函数也是方便的

/**
判断能否被已知的且小于x的素数所整除,若不能,则x为素数 
@param x   待判断是否为素数的正数
@param KnownPrimes 小于x的所有素数构成的数组
@param number0fKnownPrimes  数组KnownPrimes的大小 
*/ 
 int isPrime(int x, int KnownPrimes[], int number0fKnownPrimes)
 {
 	int i;
 	int ret = 1;   //素数:1   非素数:0
 	for( i=0 ; i<number0fKnownPrimes; i++){
 		if( x%KnownPrimes[i]==0 ){
 			ret = 0;
 			break;
		}
	}
	return ret;
 }

二、构造素数表

1.方案一:对于每个数判断是否为素数,如果是素数则计入数组

由于前三种素数判断函数的参数和第四种素数判断函数的参数不同,故在声明时是不同的,在调用函数时也需要注意

需要注意:不能用变量声明数组大小的同时初始化,即int prime[number] ={2}会报错

#include<stdio.h>
#include<math.h>   // sqrt() 

//int isPrime(int x);  // 对应前三种素数判断函数 
int isPrime(int x, int KnownPrimes[], int number0fKnownPrimes); // 被已知的且小于x的素数所整除法
 
int main()
{
	const int number = 10; // 素数表最大包括10个素数
	int prime[10] = {2}; // 初始化,直接写入2,剩余数组元素初始化为0,另外,如果数组大小定义为number会报错,原因是:不能用变量声明数组大小的同时初始化
	int count = 1; // 计数素数表中素数的个数
	int i = 3; //从3开始判断是否为素数
	
	while( count<number ){
		if( isPrime(i, prime, count) ){  // 被已知的且小于x的素数所整除法 
		// if( isPrime(i) ){   //是素数时返回值为1 ,对应前三种素数判断函数
			prime[count++] = i; //如果i是素数,将其写入数组下标count位置,并使count=count+1,指向下一个素数应该写入的数组位置 
		}
		i ++;
	} 
	// 输出质数表
	for( i=0 ; i<number ; i++ ){
		printf("%d", prime[i]);
		if( (i+1)%5 ) printf("\t");  //5个数字一行制表 
		else printf("\n");
	} 
	 
	return 0;
}

对于程序往往需要进行调试,可以用大括号内部放置调试语句,内部的本地变量对外部语句不会造成影响,方便调试,例如我们可以在上面的代码中加一些语句查看具体的运行过程

// 加入调试语句(过程展示)
#include<stdio.h>
#include<math.h>   // sqrt() 

//int isPrime(int x);  // 遍历 
int isPrime(int x, int KnownPrimes[], int number0fKnownPrimes); // 被已知的且小于x的素数所整除法
 
int main()
{
	const int number = 10; // 素数表最大包括10个素数
	int prime[10] = {2}; // 初始化,直接写入2,剩余数组元素初始化为0
	int count = 1; // 计数素数表中素数的个数
	int i = 3; //从3开始判断是否为素数
	
	{  // 调试用(加表头) 
		int i;
		printf("\t\t\t");
		for( i=0 ; i<number ; i++ ){
			printf("%d\t", i); // 展示数组下标 
		} 
		printf("\n"); 
	}
	
	while( count<number ){
		if( isPrime(i, prime, count) ){  // 被已知的且小于x的素数所整除法 
		// if( isPrime(i) ){   //是素数时返回值为1 ,遍历 
			prime[count++] = i; //如果i是素数,将其写入数组下标count位置,并使count=count+1,指向下一个素数应该写入的数组位置 
		}
	
		{  // 调试用 
			printf("i=%d\t count=%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)%5 ) printf("\t");  //5个数字一行制表 
		else printf("\n");
	} 
	 
	return 0;
}

2.方案二:构造n以内(不含n)的素数表,可:①令x=2; ②将2x,3x,4x,...所有满足ax<n的整数标记为非素数;③令x到下一个没有被标记为非素数的数,重复步骤②,直至n以内所有数都尝试完毕

伪代码为:

 

// 构造质数表
#include<stdio.h>

int main()
{
	int n;
	printf("您想构造的素数表范围为小于:");
	scanf("%d", &n);
	int isPrime[n];  // 储存对应下标的数字是否为素数的指示值,例如isPrime[2]=1则表示2是素数 
	int i,j;
	// 数组初始化 
	for( i=0 ; i<n ; i++){
		isPrime[i] = 1; 
	} 
	// i遍历2至n-1的数,如果i是素数,则j从2倍开始,满足j*i<n的整数j*i标记为非素数
	for( i=2 ; i<n ; i++){  //从2开始对于质数才有意义 
		if( isPrime[i]==1 ){
			for( j=2 ; j*i<n ; j++){ //j表示倍数 
				isPrime[j*i] = 0;
			}
		}
	} 
	// 质数表输出 
	for( i=2 ; i<n ; i++){
		if( isPrime[i] ){
			printf("%d\t", i);
		}
	} 
	printf("\n");
	
	return 0; 
 } 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值