Eratosthenes筛选法与欧拉筛选法

Eratosthenes筛选法与欧拉筛选法
由于一个合数总是可以分解成若干个质数的乘积,那么如果把质数的倍数都去掉,那么剩下的就是质数了.Eratosthenes筛选法的思想特别简单:对于不超过n的每个非负整数p,删除2p,3p,4p,...,当处理完所有数之后,还没有被删除的就是素数.如果用vis[i]表示i已经被删除,则筛选法的代码可以写成:
void isprime(int n)///筛选1-n的素数
{
    memset(vis,0,sizeof(vis));
    for(int i = 2; i <= n; i++)
        for(int j = 2 * i; j <= n; j += i)
            vis[j] = 1;
}
尽管代码已经相当高效了,但仍然可以进行改进.首先,在"对于不超过n的每个非负数p"中,p可以限定为素数--只需在第二重循环前加一个判断if(!vis[i])即可.另外,内层循环也不必从* 2开始--它已经在= 2时被筛选了.改进后代码如下:
void isprime(int n)///筛选1-n的素数
{
    memset(vis,0,sizeof(vis));
    int m = sqrt(n + 0.5);
    for(int i = 2; i <= m; i++)
    {
        if(!vis[i])
        {
            for(int j = i * i; j <= n; j += i)
                vis[j] = 1;
        }
    }
}

Eratosthenes筛选法虽然效率高,但是Eratosthenes筛选法做了许多无用功,一个数会被筛到好几次,最后的时间复杂度是O(nloglogn),对于普通素数算法而言已经非常高效了,但欧拉筛选法的时间复杂度仅仅为O(n).

欧拉筛选法的思想就是不做无用功,原本Eratosthenes筛法的第一重循环是用来找素数,然后把素数的倍数标记,而欧拉筛法换了一个角度,第一位是找素数没有问题,但是标记的时候用的是所有数.欧拉筛选法在数据小的时候不如Eratosthenes筛选法快,反而是数据变大以后,两者差距变得越来越明显,欧拉筛选法明显快于Eratosthenes筛选法.欧拉筛选法代码如下:

const int Max = 100002;
int Prime[Max];
bool vis[Max];
void prepare()
{
    int num = 0;
    memset(vis,true,sizeof(vis));
    for(int i = 2; i <= Max; ++i)
    {
        if(vis[i])
            Prime[++num] = i;
        for(int j = 1; j <= num; ++j)
        {
            if (i * Prime[j] > Max)
                break;
            vis[i * Prime[j]] = false;
            if (i % Prime[j] == 0)
                break;
        }
    }
}


已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页