整数n分解成素数乘积c语言,关于几种求素数的方法(C语言描述)

求出3到50w范围内所有的素数。

这类问题在C语言题目中经常会遇见。同样,大素数的研究对于密码学也起到了重要的作用。那么对于C语言的初学者,该如何编写程序计算素数呢?

1.

首先从素数的定义来看,“一个大于1的自然数,如果除了1和它自身外,不能被其他自然数整除的数”。除了一和他自身外,没有其他因数,那么最粗暴的算法就出来了:

遍历所有所有大于一,小于他自身的整数,如果没有数能整除他,他就是素数。

#include

#include

int

main(){

int i,j,a,b;

a=clock();

for(i=3;i<500000;i++){

for(j=2;j

if(i%j==0){

goto table;

}

}

table:;

}

b=clock();

printf("%d\n",b-a);

return 0;

}

上述代码就是实现了这个算法,当出现因数,直接跳到下一个数字。

经过测试,执行该代码的时间是33449ms。

a4c26d1e5885305701be709a3d33442f.png

明显对于一个求素数的算法来说,时间太长了。如果范围扩大到5000000,甚至50000000,耗费时间更是无法想象。那么如何去改进呢?

2.

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

#include

#include

#include

int main(){

int i,j,a,b;

a=clock();

for(i=3;i<500000;i++){

for(j=2;j<=sqrt(i);j++){

if(i%j==0){

goto table;

}

}

table:;

}

b=clock();

printf("%d\n",b-a);

return 0;

}

因数对中的较小值的最大值,自然就是其自身的平方根了。在这之后的因数都能对应一个在这之前的因数。所以如果在这之前没有因数,那么在这之后也同样没有因数。

a4c26d1e5885305701be709a3d33442f.png

这可以说是个相当大的改进了,大大减少了遍历次数,程序执行时间为234ms。

3.

除了2以外,所有的素数都是奇数。那么我们就可以先将偶数排除,再来判定质数

#include

#include

#include

int main(){

int i,j,a,b;

a=clock();

for(i=3;i<500000;i++){

if(i%2==0) goto table;

for(j=3;j<=sqrt(i);j+=2){

if(i%j==0){

goto table;

}

}

table:;

}

b=clock();

printf("%d\n",b-a);

return 0;

}

因为先一步排除了偶数, 所以寻找因数便不必再遍历偶数因数。因为奇数的因数一定是奇数。

a4c26d1e5885305701be709a3d33442f.png

进一步的优化,现在程序执行时间仅有109ms。

4.

我们做数学题时,都知道平方根并不好算。同样对于计算机来说,平方根计算也会消耗大量时间。所以我们可以先一步计算平方根,以使其不用在每次比较时都去计算。

#include

#include

#include

int main(){

int i,j,a,b;

double sq;

a=clock();

for(i=3;i<500000;i++){

if(i%2==0) goto table;

sq=sqrt(i);

for(j=3;j<=sq;j+=2){

if(i%j==0){

goto table;

}

}

table:;

}

b=clock();

printf("%d\n",b-a);

return 0;

}

a4c26d1e5885305701be709a3d33442f.png

这样程序的执行时间又缩短了一倍,现在只有46ms了。

5.

不要以为数论就是一堆没用的理论知识。算术基本定理,现在是用上它的时候了。

任何一个大于1的自然数

N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积。

那么我们只需要遍历素数因数就好了嘛。

至于能成为因数的0素数有哪些呢?

不要忘了我们是从小到大寻找的素数,现在可以用到前面的结果了。#include

#include

#include

int ar[300000];

int main(){

int i,j,k=0,a,b;

double sq;

a=clock();

for(i=3;i<500000;i++){

if(~i&1) goto table;

sq=sqrt(i);

for(j=0;ar[j]<=sq&&j

if(i%ar[j]==0){

goto table;

}

}

ar[k]=i;

k++;

table:;

}

b=clock();

printf("%d\n",b-a);

return 0;

}

把前面每一个素数放入一个数组,以此来寻找素数因数。

a4c26d1e5885305701be709a3d33442f.png

现在整个程序的执行时间只需要15ms了!

从最开始的3万3千毫秒,到现在的15毫秒,整整缩短了2200多倍。可见算法对于一个程序是多么重要。

最后再贴上一段程序,思考一下这一段与上一段有什么区别,以及为什么要这么做

#include

#include

#include

int

ar[300000];

int

main(){

int i,j,k=0,a,b;

double sq;

ar[0]=2;

a=clock();

for(i=3;i<5000000;i++){

if(~i&1) goto table;

sq=sqrt(i);

for(j=0;ar[j]<=sq;j++){

if(i%ar[j]==0){

goto table;

}

}

ar[k]=i;

k++;

table:;

}

b=clock();

printf("%d\n",b-a);

return 0;

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值