我们经常可能会遇到这样的题目,它要求我们求出100以内的素数表,或者说给定一个数,得到它的质因子乘积和,比如,
6=2* 3,8=2* 2* 2等等,这里的2以及3,就都是素数,要想解决这类问题,就不可避免地要实现求素数这个程序,下面就来具体讲解一下。
一般求素数:
思路:对每一个数进行判断,判断是素数返回一个值,不是的话再返回另一个值,故这里有一个判断函数,另外还要有一个包装素数的函数,即若一个数是素数,则把它送到一个特定的数组里面,方便输出。
另外还要知道,1不是素数,应列为特殊情况。
具体实现代码如下:
#include <cstdio>
#include <math.h>
int prime[50],p=0;
bool is_prime(int n)//判断函数
{
if(n<=1)
{
return false;
}
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
{
return false;
}
}
return true;
}
void F_prime()//封装函数
{
for(int i=1;i<=100;i++)
{
if(is_prime(i)==true)
{
prime[p++]=i;//如果是素数,则送入prime数组
}
}
}
int main()
{
F_prime();//不要忘了调用封装函数
for(int i=1;i<=p-1;i++)
{
printf("%d ",prime[i]);
}
return 0;
}
【注意点】:有的人可能会试图将两个函数融合为一个函数,这是可行的,不过相对更容易出现错误,一般情况下选择两个独立函数求素数比较好。另外,这种方法求素数的时间复杂度为 O(n*n^(1/2)),这种方法对n小于10000的情况下来说没有问题,但若是更大的n值就有必要改进算法。
改进版求素数:
思路:不管要求多少个素数,只要是从1开始枚举,我们就可以肯定 2 一定是素数,那么既然 2 是素数,那么它的倍数 2,4,6,8等所有比n小但却是2的倍数的就都不是素数,我们可以把这些不符合条件的数筛选出去,从而减少了运算量。
代码如下:
#include <cstdio>
const int maxn=10001;//这里的maxn设为10001,它在n小于17000左右以下的数都能求得素数表,如需要还可增大maxn的值
int prime[maxn],p=0;
bool flag[maxn];
void Q_prime(int n)
{
for(int i=2;i<n;i++)
{
if(flag[i]==false)
{
prime[p++]=i;
}
for(int j=2*i;j<n;j+=i)
{
flag[j]=true;
}
}
}
int main()
{
int n;
scanf("%d",&n);
Q_prime(n);
for(int i=0;i<p;i++)
{
printf("%d ",prime[i]);
}
return 0;
}
【注意点】这种方法求素数的时间复杂度为 O(nloglogn),相对上个来说改进了一些,当然还有更加高效的算法,但不属于初学者范畴,以后有机会可以了解。
好了,学习完求素数的方法,对于给定一个数,求质因子乘积的问题你还有没有思路呢?让我们共同来探讨一下:
一个例子:8=2* 2* 2以及180=2* 2* 3* 3* 5 ;
可以看到,分解出的质因子都是从2开始,这是素数表中最小的一个素数,当然也并不排除从3或者从5开始的情况,但至少我们应该从2开始枚举,在哪里枚举?当然是在素数表里。
另外,如果一个素数满足,怎么知道它需要多少个?例如180中,2需要两个,3也需要两个,5需要一个,我们可以这样,从2开始枚举,如果满足,怎样才算满足?180%2=0就是满足,如果2满足就除以2,即180/2,得到90,继续判断2是否满足,可见90%2=0,依然满足,之后90/2=45,45%2!=0,故2不再满足,故得到满足条件的2只有两个,之后判断下一个素数3。就是这么一个过程,我们可以把它设计成一个函数。
素数表的范围怎样选取?一般来说,素数表的上限不会太大,不过还有一种特殊的情况需要注意,那就是素数的质因子分解就是它本身,例如97=97;以及不是素数的1=1;这些都需要进行特殊判断。
具体完整代码如下,请好好体会:
#include <cstdio>
#include <math.h>
const int maxn=100001;
int prime[maxn],p=0;
bool is_prime(int n)//素数判断函数
{
if(n<=1)
{
return false;
}
for(int i=2;i<=sqrt(n);i++)
{
if(n%2==0)
{
return false;
}
}
return true;
}
void F_prime()//素数封装函数
{
for(int i=1;i<=maxn;i++)
{
if(is_prime(i)==true)
{
prime[p++]=i;
}
}
}
struct factor{
int x;
int cont;
}fac[10];//构造一个结构体,x是质因子,cont是它的个数
int main()
{
F_prime();//封装完成,可以开始枚举
int n,num=0;//num是不同质因子的个数,与相同质因子的个数cont区分开
scanf("%d",&n);
if(n==1)//判断等于1的特殊情况
{
printf("1=1");
return 0;
}
printf("%d=",n);
for(int i=0;i<=sqrt(n);i++)
{
if(n%prime[i]==0)//该素数满足
{
fac[num].x=prime[i];//记录该质因子
fac[num].cont=0;
while(n%prime[i]==0)//求cont的个数
{
fac[num].cont++;
n/=prime[i];
}
num++;
}
if(n==1)
{
break;
}
}
if(n!=1)
{
fac[num].x=n;
fac[num++].cont=1;//注意这里是num++,这里是为了保证下面的for循环不管怎样都至少能循环一次
}
// for(int i=0;i<num;i++)//下面编写了两种输出方式,可以根据情况自由选取
// {
// if(i>0)
// {
// printf("*");
// }
// printf("%d",fac[i].x);
// if(fac[i].cont>1)
// {
// printf("^%d",fac[i].cont);
// }
// }
for(int i=0;i<num;i++)
{
if(i>0)
{
printf("*");
}
printf("%d",fac[i].x);
while(fac[i].cont>1)//已经计数过一次,故这里减一次
{
printf("*%d",fac[i].x);
fac[i].cont--;
}
}
return 0;
}