素数筛的算法感悟

前言:

   对于一个数是否为素数的求解,我相信大家并不陌生。我们都知道素数的定义是如果某一个数除了1和它本身外,没有其他的因子了,那么我们就可以判定该数为素数。大家初学时求解并列举素数时写的代码一般是下面这个样子的,该函数的时间复杂度为O(N);

代码一:

#include<stdio.h>

int prime(int n) {

    for (int i = 2; i < n; i++) {

        if (n % i == 0) return 0;

    }

    return 1;

}

int main()

{

    int n = 20;

    for (int i = 2; i <= n; i++) {

        if (prime(i) == 0) {

            printf("%d\t", i);

        }

        

    }

    return 0;

}

 

当然我还可以将上面的代码进行优化一些,将主函数中条件判断语句修改为,这样就可以减少重复判断和过多的行缩进;其次我们其实不必要在循环时从2到n,其实从i=2到i=sqrt(n)就可以了,因为如果一个数不为素数,那么它的因子必然分布在sqrt(n)的两端,故我们只需要循环到根号下n这个位数就可以了。这样就可以把代码的时间复杂度降到O(sqrt(N));

代码二:

#include<stdio.h>

 

 int  prime(int n) {

        for (int i = 2; i * i < n; i++) {

        if (n % i == 0) return 0;

        

    }

         return 1;

   

}

 int main() {

         int n=20;

       for (int i = 2; i <= n; i++) {

          if (!prime(i)) continue;

          printf("%d\n", i);

        

    }

         return 0; 

}

 

结果为:

 

当然,这不是最好的寻找素数的算法,我们可以进一步优化使之时间复杂度降低到O(nloglogn)。我们可以用一种叫做素数筛的算法来判定并列举出素数。

素数筛:我们定义一个数组,给定一个范围,比如求出2-20之内有哪些素数,如果是素数就将其标记为0,并放入数组中,经过数学推导我们知道如果一个数为素数,那么它的倍数必为合数,我们当判定一个数为素数后紧接着下面我们就可以将其所有的倍数标记为1,。这样一个范围内的所有素数和合数就都找出来了。

代码三:

#include<stdio.h>

const int MAX = 20;

 

int prime[MAX];//建立一个数组,用来标记素数并在后期来存储素数

 

void prime_sort() {

for (int i = 2; i <= MAX; i++) {

    if (prime[i]) continue;//如果为0,跳过认定为素数,跳过这次循环,将素数的倍数标定为合数

    prime[++prime[0]] = i;

    for (int j = i; j <= MAX / i; j++) {

    prime[j * i] = 1;

    }

}

    return;

}

int main() {

    prime_sort();

    for (int i = 1; i <= prime[0]; i++) {

    printf("%d\n", prime[i]);

    }

    return 0;

}

 

  

 

posted @ 2021-03-28 18:37  花瓣飘落的地方  阅读(78)  评论(0编辑  收藏  举报