素数筛选法

当一个数不算大的时候,可以用普通的求素数的方法去求,但是如果一个数过大的话,就像让求1-十亿之间素数的个数,普通方法就不行了,这事就需要用到素数筛选法,他的时间复杂度是O(n),尽管不算很好,但是,也算是目前为止比较快的一种方法了,它是以空间换取时间,现在的计算机,空间有的是,但是时间是非常珍贵的。效率问题特别重要。他的原理就是标记,防止重复判断,这样提高了效率。就像2是素数,所有是2的倍数的肯定都不是素数,这时候标记上,接着判断3是素数,所有是3的倍数的都肯定不是素数,这时就要标记上,以此下去,执行到根下(总数),这样就会得到一个素数表,所有没有被标记的都是素数,下面是具体的代码实现,代码里面有注释。写的很清楚。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #define MAX 1000000000//定义一个数组长度
 5 bool prime[MAX + 1];//素数表
 6 int main()
 7 {
 8     int i, j, count = 0;//count为计数器
 9     memset(prime, true, sizeof(prime));//初始化,将prime数组全部都初始化为true
10     prime[0] = prime[1] = false; prime[2] = true;//0,1都不是素数,所以为false,2是素数,所以为true
11     for(i = 2; i * i <= MAX; i ++)/*从2开始进行遍历, i * i <= MAX 就等价于 i < sqrt(MAX);但是前者更不容易出错
12      具体为什么是sqrt就不用说了吧,普通的方法中也有这个*/   
13     {
14         if(prime[i])//如果没有被标记的话将它的倍数的数标记(标记就是将它赋值为false)
15         {
16             for(j = i + i; j <= MAX; j += i)//因为是从2开始的,所以j = i * i 就行了,最小的一个他的倍数的就是i * i了,不可能有比这个更小的了
17                 prime[j] = false;//标记为false
18         }
19     }
20     for(i = 2; i <= MAX; i ++)//遍历一下,找出所有的素数来
21         if(prime[i])
22                 count ++;//如果没有被标记,计数器++
23     printf("count is :%d\n", count);
24     return 0;
25 }

这时最基础的,当然还可以进行改进,改进的越多,执行效率就越快,例如:因为偶数不可能为素数,它是肯定能被2整除的,所以可以舍掉所有的偶数,这样会减少一半的时间,当然空间也会减少一半,如果十亿的话,开个5亿的数组就行了,for循环中的i 应该是从3开始了,然后一次加2,这样标记会更快,具体代码就不实现了。大致原理差不多。这时一个非常基础的算法。素数也是用到的比较多的。当然也可以琢磨点在改进改进,目前为止我没有想到更好的,如果有哪位大神有更好的方法,麻烦留一下言告知一下,谢谢!

posted @ 2014-08-29 15:31  Howe_Young  阅读(6090)  评论(0编辑  收藏  举报