素数的生成--筛选法

Posted on 2013-01-13 23:49  蛇小狼  阅读(223)  评论(0编辑  收藏  举报

基础思路

"""
一个简单的筛素数的过程:n=30。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

第 1 步过后2 4 ... 28 30这15个单元被标成false,其余为true。
第 2 步开始:
 i=3;  由于prime[3]=true, 把prime[6], [9], [12], [15], [18], [21], [24], [27], [30]标为false.
 i=4;  由于prime[4]=false,不在继续筛法步骤。
 i=5;  由于prime[5]=true, 把prime[10],[15],[20],[25],[30]标为false.
 i=6>sqrt(30)算法结束
"""

def imouren_primes(n):
    maps = n*[True]
    maps[0] = False
    maxs = int(n**0.5+1)
    for i in xrange(1,maxs):
        if maps[i]:
            maps[i::i+1] = len(maps[i::i+1])*(False,)
            maps[i] = True
    res = [i+1 for i, v in enumerate(maps) if v]
    return res

继续优化

"""
则由于只存3 5 7 9 11 13 15 17 19 21 23 25 27 29,只需要14个单元
第 1 步 把14个单元赋为true (每个单元代表的数是2*i+3,如第0单元代表3,第1单元代表5...)
第 2 步开始:
     i=0;  由于prime[0]=true, 把 [3], [6], [9], [12]标为false.
     i=1;  由于prime[1]=true, 把 [6], [11]标为false
     i=2  2*i+3>sqrt(30)算法结束
这样优化以后总共只走6个单位时间
"""
def imouren_primes2(n):
    maps = (n-1)//2*[True]
    maxs = int(n**0.5+1)
    for i in xrange(len(maps)):
        if 2*i+3 > maxs:
            break
        if maps[i]:
            maps[i::2*i+3] = len(maps[i::2*i+3])*(False,)
            maps[i] = True
    res = [(i+1)*2+1 for i, v in enumerate(maps) if v]
    res.insert(0,2)
    return res

再次优化

"""
比如我们看到的,i=0与i=1时都标了[6],这个就是重复的计算
我们可以发现一个规律,那就是3(即i=0)是从下标为[3]的开始筛的,5(即i=1)是从下标为[11]开始筛的(因为[6]
已经被3筛过了)。然后如果n很大的话,继续筛。7(i=2)本来应该从下标为[9]开始筛,但是由于[9]被筛过了,而
[16]也已经被5(i=1)筛过了。于是7(i=2)从[23](就是2*23+3=49)开始筛。
于是外围循环为i时,内存循环的筛法是从 i+(2*i+3)*(i+1)即i*(2*i+6)+3开始筛的。
"""
def imouren_primes3(n):
    maps = (n-1)//2*[True]
    maxs = int(n**0.5+1)
    for i in xrange(len(maps)):
        if 2*i+3 > maxs:
            break
        if maps[i]:
            maps[i*(2*i+6)+3::2*i+3] = len(maps[i*(2*i+6)+3::2*i+3])*(False,)
            maps[i] = True
    res = [(i+1)*2+1 for i, v in enumerate(maps) if v]
    res.insert(0,2)
    return res