一个快速法求素数的程序

闲暇时写了一个找出小于某个数字的素数的程序。
最常见的方法是筛选法吧。原理大致如下:
若要求得16以内的所有素数,
1)在数组中存放一下数据:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2)
先筛选掉是2的倍数:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
同理,继续筛选掉3的倍数.
当要筛选4的倍数的时候,由于4已经被筛选过了,所以4的倍数也必定筛选过了。因而跳过4,到5.剩下的步骤就类似了。
实际编程的时候,对一个数组进行操作。首先初始化数组,令所有元素都为0.
const int c_size = 100;
int *data = new int[c_size+1];
memset( data, 0, sizeof(int)*(c_size+1) );
data浪费了第一个空间data[0],为了简化编程,使用data[100]。
使用筛选法的时候,将筛选过的元素置为-1。输出结果的时候,仅打印data[i]的值为0的下标i。
for (int i=2; i<=data_size; i++)
{  
        if (data[i] == 0)
            cout << i << "/t";     
}
下面给出整个算法的完整代码:
#include <iostream>         //use cin and cout
using namespace std;
 
 
 
//计算2到c_size范围内的素数
const int c_size = 100;
 
 
void print(int *data, int data_size)
{
    int num = 0;
 
    for (int i=2; i<=data_size; i++)
    {  
        if (data[i] == 0)
            cout << i << "/t";     
    }
 
    cout << endl;
}
 
 
//使用筛选法计算素数
void cal_prime(int *data, int data_size)
{
    //从2开始使用筛选法计算
    for (int i=2; i<=data_size; i++)
        for (int j=2; i*j<=data_size; j++)
        {
            //如果该数尚未筛选过
            //则标记该数选中
            if (data[i*j] == 0)
                data[i*j] = -1;
            //如果已经筛选过,则跳出改次筛选
            //进入下次筛选
            else
                continue;
        }
}
 
 
int main()
{
    //定义数组并初始化
    //浪费第一个数组空间
    int *data = new int[c_size+1];
    memset( data, 0, sizeof(int)*(c_size+1) );
 
 
    //计算素数
    cal_prime(data, c_size);
 
    //打印计算出的素数
    print(data, c_size);
 
    return 0;
}
 
 
有没有更快的算法呢?偶尔在图书馆看到了另外一种算法,其大致思想如下:
1)在给定范围内,挑出6n±1的数字;
2)计算根号下(给定范围)内的所有素数(除了2,3)。比如要求出在100内的素数,先要求出在sqrt(100)内的素数,即10以内的素数(2,3,5,7)。抛去2,3,得到的结果为5,7.得到一个检验数组
3)将第一步得到的6n±1数组的每个元素用检验数组中的素数来测试,如果不能被检验数组除尽,则该数必为素数。
证明我忘记了,在图书馆看到的。下面举一个例子,求100以内的素数。
1)将100以内6n±1的数字挑选出来。结果为:
5   7   11 13 17 19 23 25 29 
31 35 37 41 43 47 49 53 55 
59 61 65 67 71 73 77 79 83 
85 89 91 95 97
2)计算出10以内的除了2、3外的素数,为5跟7.
3)分别用5和7来检验1)数组中的数字。比如11不能被5和7整除,所以是素数,25能被5整除,所以不是素数。依次类推。得到的结果为:
5   7   11 13 17 19 23 25 29 
31 35 37 41 43 47 49 53 55 
59 61 65 67 71 73 77 79 83 
85 89 91 95 97
其中红色数字为能被5或7整除的数字。
最后,加上2,3即为所有100以内的素数。
在编程的时候,求10以内的素数用筛选法,然后再用该算法求出素数。具体程序如下:
#include <iostream>         //use cin and cout
#include <vector>           //use vector
#include <cmath>            //use sqrt()
using namespace std;
 
//void cal_prime(int *data, int data_size)函数为之前定义的筛选法求素数
 
 
//初始化数组,将6n+1,6n-1的数字加入数组中
void initialize_vector(vector< int > &data)
{
 
    int i = 1;
    while(1)
    {
        int n = 6* i;
        if (n<c_size)
        {
            data.push_back(n-1);
            data.push_back(n+1);
        }
        else if (n == c_size)
            data.push_back(n-1);
        else
            break;
        i++;
    }
}
 
 
//快速计算该数是否为素数
//将该数字与检验数组中的所有数字相除
int quick(int item, const vector< int > prime)
{
    for (int i=0; i<prime.size(); i++)
    {
        //一旦能被检验数组中的素数除尽
        //该数是素数,返回-1标志
        if (item%prime[i] == 0)
            return -1;
    }
 
    //如果检验数组的数字都不能除尽该数
    //说明是素数,返回该数字.
    return item;
}
 
 
 
void quick_cal_prime(void)
{
    vector< int > data;
 
 
    int i = 1;
    initialize_vector(data);
 
 
    //检验数组的产生
    //使用了筛选法求素数
 
    //1)用筛选发求出sqrt(c_size)内的所有素数
    int t_size = sqrt(c_size);
    int *temp = new int[t_size+1];
    memset( temp, 0, sizeof(int)*(t_size+1) );
 
    cal_prime(temp, t_size);
 
    //2)将素数放入检验数组
    vector< int > temp_prime;
    for (i=5; i<=t_size; i++)
        if (temp[i] == 0)
            temp_prime.push_back(i);
 
 
    //3)对素数进行快速检验
    for (i=0; i<data.size(); i++)
        data[i] = quick(data[i], temp_prime);
 
    //4)打印所有的c_size范围内的所有素数
    //需要手工补充2和3
    //cout << 2 << "/t" << 3 << "/t";
    for (i=0; i<data.size(); i++)
        if (data[i] != -1)
        cout << data[i] <<endl;
 
}
 
实际测试的时候,发现快速发并不”快”,为什么呢?从理论上来说快速法减少了筛选法筛选的次数,估计有两个地方阻碍了它的快速:1)快速法编程的时候使用了vector,效率上不如直接使用数组快;2)快速法使用了多余的语句(为了编程方便).
或许还有其它的原因,比如一个根号运算.
如果大家有更好的算法或者更高效的编程方法请告诉我,谢谢.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值