1. 程式人生 > >快速篩法求素數

快速篩法求素數

這個有點難理解,我也組織不好語言,再次轉發一波。轉載出自https://blog.csdn.net/stack_queue/article/details/53560887

求素數是程式設計比賽中經常遇到的問題,最基本的方法是通過素數的定義直接判斷,只能被1和它本身整除的數就是素數了。這種方法適合判斷單個數是否為素數,當要求一個範圍內素數而這個範圍又比較大時,這種方法就不太使用了,甚至程式要執行幾分鐘才能算出結果。

篩法的思想是去除要求範圍內所有的合數,剩下的就是素數了,而任何合數都可以表示為素數的乘積,因此如果已知一個數為素數,則它的倍數都為合數。

普通的篩法:

#include<stdio>
#include<cstring>
using namespace std;
#define MAX 100000//求MAX範圍內的素數
long long su[MAX],cnt;
bool isprime[MAX];
void prime()
{
    cnt=1;
    memset(isprime,1,sizeof(isprime));//初始化認為所有數都為素數
    isprime[0]=isprime[1]=0;//0和1不是素數
    for(long long i=2;i<=MAX;i++)
    {
        if(isprime[i])//儲存素數
        {
            su[cnt++]=i;
        }
        for(long long j=i*2;j<=MAX;j+=i)//素數的倍數都為合數
        {
            isprime[j]=0;
        }
    }
}
int main()
{
    prime();
    for(long long i=1;i<cnt;i++)
        printf("%d  ",su[i]);
    return 0;
}


普通的線性篩法雖然大大縮短了求素數的時間,但是實際上還是做了許多重複運算,比如2*3=6,在素數2的時候篩選了一遍,在素數為3時又篩選了一遍。如果只篩選小於等於素數i的素數與i的乘積,既不會造成重複篩選,又不會遺漏。時間複雜度幾乎是線性的。

優化後的線性篩法:

#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 100000//求MAX範圍內的素數
long long su[MAX],cnt;
bool isprime[MAX];
void prime()
{
    cnt=1;
    memset(isprime,1,sizeof(isprime));//初始化認為所有數都為素數
    isprime[0]=isprime[1]=0;//0和1不是素數
    for(long long i=2;i<=MAX;i++)
    {
        if(isprime[i])
            su[cnt++]=i;//儲存素數i
        for(long long j=1;j<cnt&&su[j]*i<MAX;j++)
        {
            isprime[su[j]*i]=0;//篩掉小於等於i的素數和i的積構成的合數
        }
    }
}
int main()
{
    prime();
    for(long long i=1;i<cnt;i++)
        printf("%d  ",su[i]);
    return 0;
}

參考:https://blog.csdn.net/Dinosoft/article/details/5829550