素數判斷方法總結

今天想總結一下素數的幾種求法
暴力方法:
最簡單的方法就是從2開始循環到n,如果沒有一個數能被n整除就是素數

#include<stdio.h>
int isPrime(int n) {
    for(int i=2; i<n; i++) {
        if(n%i == 0)
            return 0 ;
    }
    return 1 ;
}
int main() {
    int x ;
    scanf("%d", &x) ;
    if(isPrime(x))
        printf("YES\n") ;
    else
        printf("NO\n") ;
    return 0 ;
}

這個方法是最簡單粗暴的,但是也是效率最低的需要循環到n-1,可以進行一點改進,循環的判斷條件只需要到n/2+1就可以了

int isPrime(int n) {
    for(int i=2; i<n/2+1; i++) {
        if(n%i == 0)
            return 0 ;
    }
    return 1 ;
}

這樣循環的次數還是不夠少,其實只需要判斷到根號n次就行,一般來說可以使用sqrt(n)來求根號n,我們還可以用 i*i<n來實現

int isPrime(int n) {
    for(int i=2; i*i<n; i++) {
        if(n%i == 0)
            return 0 ;
    }
    return 1 ;
}

其實還可以繼續優化這個方法,因爲除了2以外的所有偶數都不可能是素數,所以我們只需要判斷奇數就行

bool isPrime(int n) {
    if(n%2==0 && n!=2)  //除了2以外的所有偶數都不是素數
        return false ;
    else if(n == 2)
        return true ;
    for(int i=3; i*i<n; i+=2) {     //3-根號n內沒有一個數能被n整除就是素數
        if(n%i == 0)
            return false ;
    }
    return true ;
}

這是我目前能想到用暴力的方法最優的樣子,如果還有可以優化的地方歡迎指教

埃氏篩:
這個方法是通過打表找出指定範圍內所有的素數,當數字範圍小的時候用暴力沒問題但只要範圍太大就用不了了,就可以用這個方法
原理:從2開始循環,將2存入素數表中,把2所有的倍數都捨去,然後對3進行相同的操作,一直這樣循環到頭


#include<cstdio>
int isPrime[100000] ;       //記錄該點是否是素數
int prime[100000] ;         //存素數
int main() {
    int count = 0 ;         //記錄共有幾個素數
    for(int i=2; i<100000; i++) {
        if(isPrime[i] == 0) {   //從2 開始將2的所有倍數除去然後是3的倍數4的倍數…………
            prime[count++] = i ;    //將素數存入
            for(int j=i*i; j<100000; j+=i)  
                isPrime[j] = 1 ;
        }
    }
    for(int i=0; i<count; i++) {
        printf("%d ",prime[i]) ;
        if(i%10 == 0)
            printf("\n") ;
    }
    return 0 ;
}

第二層for循環中j 從 i * i 而不是從 i + i開始,因爲 i*(2~ i-1)在 2~i-1時都已經被篩去,所以從i * i開始
這個方法有個缺點就是會重複多次篩去一個點,於是就有了下一個方法

歐拉篩:
這個方法是在埃氏篩的基礎上做了一點改進,原理是把一個合數(6=2*3)通過它的最小質因子篩去

#include<cstdio>
int isPrime[100000] ;
int prime[100000] ;
int main() {
    int count = 0 ;
    for(int i=2; i<100000; i++) {
        if(isPrime[i] == 0)
            prime[count++] = i ;
        for(int j=0; j<count&&i*prime[j]<100000; j++) {   //找出由i和已得到的素數相乘得到的數
            isPrime[i*prime[j]] = 1 ;   //將由i和最小質因數相乘得到的數排除,
            if(i%prime[j] == 0)     //如果i能被已經存過的素數整除,說明在之前就由其他的i和最小質因數相乘過,不用重複查
                break ;
        }
    }
    for(int i=0; i<count; i++) {
        printf("%d ",prime[i]) ;
        if(i%10 == 0)
            printf("\n") ;
    }
    return 0 ;
}

總結:
通過寫這個求素數的不同方法,從低效的逐漸提高效率,也反應了學習編程一年的一些想法上的進步,這樣看上去還是比較開心的。所以說考慮一個問題還是要多研究多考慮深一些,不斷優化自己的代碼

發佈了22 篇原創文章 · 獲贊 58 · 訪問量 7289
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章