素數驗證演算法——直面大資料

來源:互聯網
上載者:User

標籤:

      素數的驗證,可能會被作為所謂“迴圈練習”的題目。因為其演算法實在太簡單(不知道直接暴力迴圈能不能算一種演算法)。經典的方法就是試除,用迴圈變數i從2開始到n-1,如果有模數為0的,就直接return false。到最後,還沒有模出0,就return true。這個演算法也可以最佳化n-1為sqrt(n)。原理是:設x為大於sqrt(n)的數,n=xy,則y一定小於sqrt(n),所以只要驗證到sqrt(n),就能驗證到y,相當於驗證到了x。

      以上這種暴力演算法,如果有N個數要驗證,則時間複雜度為O(sqrt(N)*N),面對類似於N=100000000的資料明顯力不從心。所以,我們可以使用篩選法:依次剔除2、3、5、7等素數的倍數,最後就能得出一張素數表。建表後,查詢素數只要O(1)的時間複雜度。但是對於以上數量級的N,仍然不能很快的求出一張素數表,消耗時間高達2.1s。所以,我們還要加以最佳化。

      眾所周知,除去2以外,所有的偶數均為合數。所以,素數表內可以除去偶數。即prime[0]代表3是否為素數,prime[1]代表5……而且,篩數也不必篩到N,只要篩到sqrt(N)即可。設key1(i)=i*2+3;key2(i)=(i-3)/2,這分別對應素數表內第i個位置表示的奇數與奇數i在素數表內的儲存位置。原來篩的時候,i*(2,3,4…)簡化為了i*(3,5,7…)。頭一次篩掉的數為key2(key1(i*i)),簡化後為(i*i)*8+3,之後每次累加的數為key2(key1(i+2))-key2(key1(i)),簡化後為i*2+3,這樣推導完成以後,程式就很容易寫了。下面給出原始碼:

#include <cstring>#include <cmath>#include <cstdio>using namespace std;const int N=100000001;const int N1=(N-3)/2;bool prime[N1+1];int tmp;int main(void){    memset(prime,true,sizeof(prime));    for (int i=0;i<(int(sqrt(N))-3)>>1;++i){        if (prime[i]){            tmp=((i*i)<<3)+3;            while (tmp<N1){                prime[tmp]=false;                tmp+=(i<<1)+3;            }        }    }    printf("%d\t",2);    for (int i=0;i<N1;++i)        if (prime[i])   printf("%d\t",i*2+3);    return 0;}

      附上各種方法的時間與記憶體佔用統計表(測試環境:MinGw4.9.2,Intel Xeon E3 1230V2,去除IO輸出時間):

  時間 記憶體
暴力試除法 N/A(太長了) 1Mb
樸素篩選法 2.1s 98Mb
最佳化後的篩選法 1.0s 50Mb

素數驗證演算法——直面大資料

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.