算法 素数筛法

来源:互联网 发布:国家电网网络大学答案 编辑:程序博客网 时间:2024/06/07 06:28

素数筛法

关键思想

素数筛法是ACM 及各大比赛中必须熟练掌握的最低级的算法,在已知某些素数的情况下对未判断的数进行筛选,筛选掉必然不是素数的数。如何对数进行筛选,依据素数的性质,某个除1以外的正整数是素数,则该数的倍数一定不是素数

举个栗子

从1-10中筛选出所有素数

步骤 当前元素 1 2 3 4 5 6 7 8 9 10 原始数组 / / 0 0 0 0 0 0 0 0 0 第一步 2 / 0 0 1 0 1 0 1 0 1 第二步 3 / 0 0 1 0 1 0 1 1 1 第三步 5 / 0 0 1 0 1 0 1 1 1 第四步 7 / 0 0 1 0 1 0 1 1 1

以第一步为例:当前元素为2,则将22=423=625=10都置为合数,即每次都将当前为素数的元素的倍数从候选的数中除去。
循环上述过程,则可得到最终的数组,数组中为0的则该元素为素数,否则为合数。

代码如下

#include <cstdio>#define MAXN 11int prime[MAXN] = {1, 1}; //第0,1个元素直接设为合数,合数设为1,素数为0int main() {    //素数筛法求素数    for (int i = 0; i < MAXN; ++i) {        if (!prime[i]) {//若该数是素数,则将该数的倍数全设为合数。            //printf("%d ",i); 答应当前元素            for (int j = 2 * i;  j <= MAXN; j+=i) {//筛选掉必然是合数的数                prime[j] = 1;            }        }    }    return 0;}

复杂度

该算法的复杂度为O(n2),但常系数非常小,实际运行时接近O(N)复杂度,并且随着筛选的进行,可以仔细思考一下,最后筛选掉的数越来越多,剩下的素数越来越小,即素数之间的间隔越来越大。

关于优化

在素数筛法的过程中,有许多重复计算的过程可以进行优化,例如上述例子中,元素6和元素10都筛选了两次,就是表格中红了两次。
下边列一下可以优化的点,就不具体实现了。
1. 避免重复筛选
2. 偶数直接可以不参与筛选,并且依据这个规则可以将数组大小优化掉一半
说明一下第二点可以优化空间的方法,例如原数组的第i个元素代表数字i是否为素数,若直接将偶数去除,则数组的第i个元素则可代表数字2i1是否为素数。

进阶

想继续学习素数有关知识的可以看看以下几个知识点

  1. 费马测试
  2. Miller-Rabin 质数测试
  3. 欧拉-雅科比测试
  4. AKS质数测试

等等素性测试算法,可能以后会在详细讨论这些算法。

1 0