试除法质数打表方法的逐步改进--经典面试题

本文探讨了试除法寻找质数的多种境界,从最基础的从2到x-1的尝试,逐步优化到仅需判断到√x,并分析了通过保存已知质数来提高效率的思想,最后指出当前方法仍有改进空间。
摘要由CSDN通过智能技术生成

试除法质数打表方法的逐步改进--经典面试题

参考博客:点击打开链接

求质数算法的N种境界 - 试除法和初级筛法


http://blog.csdn.net/wdqfzy/article/details/7034784

需求1


请实现一个函数,对于给定的整型参数 N,该函数能够把自然数中,小于 的质数,从小到大打印出来。
比如,当 N = 10,则打印出
2 3 5 7

试除法


  "试除",顾名思义,就是不断地尝试能否整除。比如要判断自然数 是否质数,就不断尝试小于 且大于1的自然数,只要有一个能整除,则 是合数;否则,是质数。
  显然,试除法是最容易想到的思路。不客气地说,也是最平庸的思路。不过捏,这个最平庸的思路,居然也有好多种境界。 

境界1


  在试除法中,最最土的做法,就是:
  假设要判断 是否为质数,就从 一直尝试到 x-1。这种做法,其效率应该是最差的。 

境界2


  稍微聪明一点点的程序猿,会想:如果有(除了自身以外的)质因数,那肯定会小于等于 x/2,所以捏,他们就从 一直尝试到 x/2 即可。
  这一下子就少了一半的工作量哦,但依然是很笨的办法。

境界3


  再稍微聪明一点的程序猿,会想了:除了2以外,所有可能的质因数都是奇数。所以,他们就先尝试 2,然后再尝试从 开始一直到 x/2 的所有奇数。
  这一下子,工作量又少了一半哦。但是,俺不得不说,依然很土。就算代码完全正确也只能得3分。

境界4


  比前3种程序猿更聪明的,就会发现:其实只要从 一直尝试到√x,就可以了。为什么只要到√x 即可?
  简单解释一下:因数都是成对出现的。比如,100的因数有:11002504255201010。看出来没有?成对的因数,其中一个必然小于等于100的开平方,另一个大于等于100的开平方。

境界5

 
   一些更加聪明的程序猿,会发现一个问题:尝试从 √x 的所有奇数,还是有些浪费。比如要判断101是否质数,101的根号取整后是10,那么,按照境界4,需要尝试的奇数分别是:3579。但 是你发现没有,对9的尝试是多余的。不能被3整除,必然不能被9整除......顺着这个思路走下去,这些程序猿就会发现:其实,只要尝试小于√x 质数即可。而这些质数,恰好前面已经算出来了(是不是觉得很妙?)。所以,处于这种境界的程序猿,会把已经算出的质数,先保存起来,然后用于后续的试除,效率就大大提高了。顺便说一下,这就是算法理论中经常提到的:以空间换时间。



#include<iostream>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const long int N=201357;//2013年5月7日
/**=======================================**/
void prime_v1(long int n)
{
    long  int i,j;
    for(i=2;i<n;i++)
    {
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                break;
            }
        }
        if(j>=i)
        {
            //cout<<setw(9)<<i;
        }
    }
     cout<<endl;
}
void test_prime_v1()
{
    long now=clock();
    prime_v1(N);
    cout<<"prime_v1 running time is: "<<(double)(clock()-now)/CLOCKS_PER_SEC<<endl;
}
/**=======================================**/
void prime_v2(long int n)
{
    long int i,j,k;
    bool flag=true;
    for(i=2;i<n;i++)
    {
        flag=true;
        k=i/2+1;
        for(j=2;j<k;j++)
        {
            if(i%j==0)
            {
                flag=false;
                break;
            }
        }
        if(true==flag)
        {
            //cout<<setw(9)<<i;
        }
    }
    cout<<endl;
}
void test_prime_v2()
{
    long now=clock();
    prime_v2(N);
    cout<<"prime_v2 running time is: "<<(double)(clock()-now)/CLOCKS_PER_SEC<<endl;
}
/**=======================================**/
void prime_v3(long int n)
{
    long int i,j,k;
    bool flag=true;
    for(i=2;i<n;i++)
    {
        flag=true;
        k=i/2+1;
        for(j=2;j<k;j%2?j+=2:j++)
        {
            if(i%j==0)
            {
               flag=false;
                break;
            }
        }
        if(flag==true)
        {
            //cout<<setw(9)<<i;
        }
    }
    cout<<endl;
}
void test_prime_v3()
{
    long now=clock();
    prime_v3(N);
    cout<<"prime_v3 running time is: "<<(double)(clock()-now)/CLOCKS_PER_SEC<<endl;
}
/**=======================================**/
void prime_v4(long int n)
{
    long int i,j;
    bool flag=true;
    for(i=2;i<n;i++)
    {
        flag=true;
        for(j=2;j<sqrt(i+1);j%2?j+=2:++j)
        {
            if(i%j==0)
            {
                flag=false;
                break;
            }
        }
        if(flag==true)
        {
            //cout<<setw(9)<<i;
        }
    }
    cout<<endl;
}
void test_prime_v4()
{
    long now=clock();
    prime_v4(N);
    cout<<"prime_v4 running time is: "<<(double)(clock()-now)/CLOCKS_PER_SEC<<endl;
}
/**=======================================**/
void prime_print(long int n)
{
    long  int i,j;
    bool flag=true;
    for(i=2;i<n;i++)
    {
        flag=true;
        for(j=2;j<sqrt(i+1);j%2?j+=2:++j)
        {
            if(i%j==0)
            {
                flag=false;
                break;
            }
        }
        if(flag==true)
        {
            cout<<std::right<<setw(9)<<i;
        }
    }
    cout<<endl;
}
int main()
{
    test_prime_v1();
    test_prime_v2();
    test_prime_v3();
    test_prime_v4();
    cout<<"*=======================================**"<<endl;
    prime_print(512);

	return 0;
}
/*********************

prime_v1 running time is: 7.893

prime_v2 running time is: 3.885

prime_v3 running time is: 1.934

prime_v4 running time is: 0.094
*=======================================**
        2        3        5        7       11       13       17       19       2
3       29       31       37       41       43       47       53       59
61       67       71       73       79       83       89       97      101
103      107      109      113      127      131      137      139      149
 151      157      163      167      173      179      181      191      193
  197      199      211      223      227      229      233      239      241
   251      257      263      269      271      277      281      283      293
    307      311      313      317      331      337      347      349      353
     359      367      373      379      383      389      397      401      409
      419      421      431      433      439      443      449      457      46
1      463      467      479      487      491      499      503      509

Process returned 0 (0x0)   execution time : 14.664 s
Press any key to continue.

*********************/



上述方法仍有改进的空间,因为for(j=2;j<k;j%2?j+=2:j++)  这里对奇偶的判断只有第一次是有效的,之后全是无效的判断,因为全是奇数了,在循环体里边增加判断语句无疑消耗了大量程序运行时间。稍后补充境界5的实验程序以及筛法的实验程序。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值