素数判断方法总结

今天想总结一下素数的几种求法
暴力方法:
最简单的方法就是从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 ;
}

总结:
通过写这个求素数的不同方法,从低效的逐渐提高效率,也反应了学习编程一年的一些想法上的进步,这样看上去还是比较开心的。所以说考虑一个问题还是要多研究多考虑深一些,不断优化自己的代码

发布了21 篇原创文章 · 获赞 51 · 访问量 3197

猜你喜欢

转载自blog.csdn.net/weixin_44689154/article/details/102172651