日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一般筛法和快速线性筛法求素数 求素数的一点总结

發布時間:2023/11/30 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一般筛法和快速线性筛法求素数 求素数的一点总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

素數總是一個比較常涉及到的內容,掌握求素數的方法是一項基本功。

基本原則就是題目如果只需要判斷少量數字是否為素數,直接枚舉因子2 。。N^(0.5) ,看看能否整除N。

如果需要判斷的次數較多,則先用下面介紹的辦法預處理。


?一般的線性篩法

首先先介紹一般的線性篩法求素數

void make_prime() ?{ ? ? ?

memset(prime, 1, sizeof(prime));

prime[0]=false; ? ??

prime[1]=false; ? ??

int N=31700; ? ? ?

for (int i=2; ?i<N; ?i++) ? ? ? ??

?if (prime[i]) { ? ? ? ? ?

primes[++cnt ]=i; ? ??

for (int k=i*i; k<N; k+=i) ? ? ? ?

prime[k]=false; ? ? ??

?} ? ? ?

return;

} ??

這種方法比較好理解,初始時,假設全部都是素數,當找到一個素數時,顯然這個素數乘上另外一個數之后都是合數(注意上面的 i*i ,? 比 i*2 要快點 ),把這些合數都篩掉,即算法名字的由來。

但仔細分析能發現,這種方法會造成重復篩除合數,影響效率。比如10,在i=2的時候,k=2*15篩了一次;在i=5,k=5*6 的時候又篩了一次。所以,也就有了快速線性篩法。

?

快速線性篩法

快速線性篩法沒有冗余,不會重復篩除一個數,所以“幾乎”是線性的,雖然從代碼上分析,時間復雜度并不是O(n)。先上代碼

?


首先,先明確一個條件,任何合數都能表示成一系列素數的積。

不管 i 是否是素數,都會執行到“關鍵處1”,


①如果 i 都是是素數的話,那簡單,一個大的素數 i 乘以不大于 i 的素數,這樣篩除的數跟之前的是不會重復的。篩出的數都是 N=p1*p2的形式, p1,p2之間不相等

?

②如果 i 是合數,此時 i 可以表示成遞增素數相乘 i=p1*p2*...*pn, pi都是素數(2<=i<=n),? pi<=pj? ( i<=j )

p1是最小的系數。

根據“關鍵處2”的定義,當p1==prime[j] 的時候,篩除就終止了,也就是說,只能篩出不大于p1的質數*i

?

我們可以直觀地舉個例子。i=2*3*5

此時能篩除 2*i ,不能篩除 3*i

如果能篩除3*i 的話,當 i' 等于 i'=3*3*5 時,篩除2*i' 就和前面重復了。

?

需要證明的東西:

  • 一個數會不會被重復篩除。
  • 合數肯定會被干掉。
  • 根據上面紅字的條件,現在分析一個數會不會被重復篩除。

    設這個數為 x=p1*p2*...*pn, pi都是素數(1<=i<=n)? ,? pi<=pj ( i<=j )?

    當 i = 2 時,就是上面①的情況,

    當 i >2 時, 就是上面②的情況, 對于 i ,第一個能滿足篩除 x 的數? y 必然為 y=p2*p3...*pn(p2可以與p1相等或不等),而且滿足條件的 y 有且只有一個。所以不會重復刪除。


    證明合數肯定會被干掉? 用歸納法吧。


    ?類比一個模型,比如說我們要找出 n 中2個不同的數的所有組合 { i , j } ,1<=i<=n, 1<=j<=n,

    我們會這么寫

    for (i=1; i<n; ++i )

    ? for (j=i+1; j<=n; ++j)

    ?? {

    ? ? .....

    ?? }

    我們取 j=i+1 便能保證組合不會重復。快速篩法大概也是這個道理,不過這里比較難理解,沒那么直觀。

    ?第一種的優化,先判斷奇偶。

    #include<iostream>

    using namespace std; ? ?

    const long N = 200000; ??

    long prime[N] = {0},num_prime = 0; ? ?

    int isNotPrime[N] = {1, 1}; ??

    int main() ? ?

    { ? ??

    ? ? ? for(long i = 2 ; i < N ; i ++) ? ? ??

    ? ? ? ? { ? ? ? ? ? ?

    if(! isNotPrime[i]) ? ? ? ? ? ? ??

    prime[num_prime ++]=i; ?

    //關鍵處1 ? ? ? ?

    for(long j = 0 ; j < num_prime && i * prime[j] < ?N ; j ++)

    ? ? { ? ? ? ? ? ? ??

    ? ? ? isNotPrime[i * prime[j]] = 1; ?

    ? if( !(i % prime[j] ) ) ?//關鍵處2 ? ? ? ? ? ? ? ? ?

    break; ? ? ? ? ??

    } ? ? ? ?

    } ? ? ? ?

    return 0; ??

    } ?

    ? ? ? 還有一種方法,即第一篇博客說的,實際上是幼拉脫斯展納篩法,但只是作為學術,不怎么常用

    int * eratosthenes(int n){
    int a=sqrt(n);
    int* array=new int[n+1];
    for(int i=0;i<n+1;i++){
    array[i]=i;
    }
    array[1]=0;
    for(int i=2;i<a+1;i++){
    if(array[i]!=0){
    for(int j=i+i;j<n+1;j+=i){
    array[j]=0;
    }
    }
    }
    return array;
    }


  • 打印質數的各種算法?http://coolshell.cn/articles/3738.html? 里面有個用C++模板實現的,純屬開闊眼界,不怎么實用。
  • 檢查素數的正則表達式??http://coolshell.cn/articles/2704.html? 數字n用? 1111。。1 (n個1)表示,純屬坑爹。
  • 總結

    以上是生活随笔為你收集整理的一般筛法和快速线性筛法求素数 求素数的一点总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。