且未

博客园 首页 新随笔 联系 订阅 管理

今天试了一下素数筛法 
要求1-100000范围内的素数,如果用自定义函数挨个求,对于大范围的求素数会非常耗时。复杂度为O(n * sqrt(n)),所以可以用素数筛法来求大范围内的素数 
说一下原理: 
开一个标记数组,全部初始化为true,0、1不是素数,直接从数组里划掉。 
从2开始,凡是2的倍数、且小于100000的,全部标记为false。 
再找2以后的、是素数的下一位数,是3 
从3开始,凡是3的倍数、且小于100000的,全部标记为false。 
再找3以后的、是素数的下一位数,是5 
从5开始,凡是5的倍数、且小于100000的,全部标记为false。 
这样循环,直到开始的位置大于100000,退出循环。 
这样,所有标记为TRUE的元素的下标全是素数。 
贴上代码

t = 2;
    memset(a, -1, sizeof(a));//-1 is prime    0 is not prime
    while(t <= 1000)
    {
        for(i=2; i<=1000; i++)
        {
            if(i * t >= 1000)
                break;
            a[i*t] = 0;
        }
        t ++;
        while(t <= 1000 && a[t] == 0)
            t ++;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

然而这样做会有重复的标记为false的过程,想要提高效率,还可以采用下面这种办法,在对大数据处理的时候会有明显的优势

    memset(a, -1, sizeof(a));
    a[0] = a[1] = 0;
    a[2] = -1;
    for(i=3; i<=5000001; i++)
        a[i] = i % 2 == 0 ? 0 : -1;
    t = sqrt(5000000);
    for(j=3; j<=t; j++)
        if(a[j])
            for(i=j*j; i<=5000000; i+=j+j)
                a[i] = 0;
    //-1 is prime        0 is not prime
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

解释一下for(i=j*j; i<=5000000; i+=j+j)这个循环 
首先从i+=j+j说起: 
首先在上面已经把所有的偶数位全部标记为false,所以,当a[j]能进入在这个for循环上面if的时候,j一定是个奇数。i的起始值是j*j所以,起始值也一定是个奇数。 
所以i一下加两个j,因为加上一个j后一定是个偶数。 
在说起始值为什么为j*j: 
像上面所说,j是个奇数。 
对于j*(j - 1),因为j - 1是个偶数,所以j * (j - 1)一定是个偶数,其所在位置一定标为false。 

对于j * (j - 2k) (k = 1, 2, 3…)j - 2k 一定是个奇数,对于任意的j * (j - 2k),一定有这样一个循环标记过j * (j - 2k):for(i=(j-2k) * (j - 2k); i<=5000000; i+= j + j),所以j * (j - 2k)一定是一个确定了的位置

https://blog.csdn.net/sdutstudent/article/details/53783051

posted on 2018-03-26 20:47  阿聊  阅读(173)  评论(0编辑  收藏  举报