暑期学习日记——超快的素数筛选法(改进)

素数筛选法:

最近发现了一个用bool数组去判断素数的方法,很强大,速度非常之快,方法是从大佬博客:https://www.cnblogs.com/wpnan/p/4073852.html 截下来的,可以看去看一下。

    素数筛法是这样的:
    1.开一个大的bool型数组prime[],大小就是n+1就可以了.先把所有的下标为奇数的标为true,下标为偶数的标为false.
    2.然后:
      for( i=3; i<=sqrt(n); i+=2 )
      {   if(prime)
          for( j=i+i; j<=n; j+=i ) prime[j]=false;
      }
    3.最后输出bool数组中的值为true的单元的下标,就是所求的n以内的素数了。
    原理很简单,就是当i是质(素)数的时候,i的所有的倍数必然是合数。如果i已经被判断不是质数了,那么再找到i后面的质数来把这个质
数的倍数筛掉。
    一个简单的筛素数的过程:n=30。
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

    第 1 步过后2 4 ... 28 30这15个单元被标成false,其余为true。
    第 2 步开始:
     i=3;  由于prime[3]=true, 把prime[6], [9], [12], [15], [18], [21], [24], [27], [30]标为false.
     i=4;  由于prime[4]=false,不在继续筛法步骤。
     i=5;  由于prime[5]=true, 把prime[10],[15],[20],[25],[30]标为false.
     i=6>sqrt(30)算法结束。
    第 3 步把prime[]值为true的下标输出来:
     for(i=2; i<=30; i++)
     if(prime) printf("%d ",i);
    结果是 2 3 5 7 11 13 17 19 23 29

内容非常清晰明了,利用bool数组去筛选也确实是普通判断素数方法的好几倍,不过观察了一下大佬的代码发现方法还可以有进一步改进,我先将大佬的原代码发上来:

 1 //用了筛法的方法:
 2 #include<stdio.h>
 3 #include<math.h>
 4 #define N 10000001
 5 bool prime[N];
 6 int main()
 7 {
 8    int i, j;
 9    for(i=2; i<N; i++)
10   if(i%2) prime=false;
11   else prime=true;
12    for(i=3; i<=sqrt(N); i+=2)
13    {   if(prime)
14        for(j=i+i; j<N; j+=i)
15
16             prime=false;
17    }
18    for(i=2; i<100; i++)//由于输出将占用太多io时间,所以只输出2-100内的素数。可以把100改为N
19     if( prime )
20
21          printf("%d ",i);
22    return 0;
23 }

可以优化的有两个地方,第一是一开始就给bool数组分配了很大的不一定需要的空间,这样有时候是很占内存的,第二就是判断素数的时候可以用位运算去判断,位运算判断奇偶数的速度大概是i%2的4倍左右,改进后的代码如下:

 1 #include<iostream>
 2 #include<math.h>
 3 #include<conio.h>
 4 #include<malloc.h>
 5 using namespace std;
 6
 7 int main(int argc, const char * argv[])
 8 {
 9     int n;
10     cin >> n;
11     bool * num = (bool *)malloc((n + 1) * sizeof(bool));//如果需要判断n以内的素数,就直接分配n+1的空间,这样就可以节省很多内存。
12     for (int i = 2; i <= n ; i++)
13     {
14         if (((1&i)==0) && (i!= 2) ) num[i] = false;//利用位运算判断奇偶
15         else num[i] = true;
16     }
17     for (int i = 3; i <= sqrt(n); i += 2)
18     {
19         if (num[i])
20             for (int j = i + i; j <= n; j += i)
21                 num[j] = false;
22     }
23     for (int i = 2; i <= n; i++)
24         if (num[i] == true )cout << i << endl;
25     _getch();//不是在vs里面运行的不需要加这一行
26     return 0;
27 }

大佬的思路是真的强,没看之前还真不知道可以利用bool数组去加快判断速度,还是有很多地方可以向大佬学习的!

原文地址:https://www.cnblogs.com/xiangqi/p/11102420.html

时间: 2024-10-10 10:23:21

暑期学习日记——超快的素数筛选法(改进)的相关文章

ZZUOJ-1222- 属于ACMer的游戏 猜素数 (某月赛,总结一下素数筛选法)

题目位置:1222: 属于ACMer的游戏 猜素数 1222: 属于ACMer的游戏 猜素数 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 88  Solved: 21 [Submit][Status][Web Board] Description ACM实验室的众大神们喜欢聚餐大家一起HAPPY 尤其卢学长喜欢请大家HAPPY,但是卢学长请吃饭有一个习惯,大家要一起玩一个热身游戏,猜素数. 游戏规则如下: 正常人的版本是这样:比如卢学长先约定一

hdu 5407 CRB and Candies(素数筛选法,除法取模(乘法逆元))

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5407 解题思路: 官方题解: The problem is just to calculate g(N) =\ LCM(C(N,0), C(N,1), ..., C(N, N))g(N) = LCM(C(N,0),C(N,1),...,C(N,N)). Introducing function f(n) =\ LCM(1, 2, ..., n)f(n) = LCM(1,2,...,n), the

HDU 2161 Primes (素数筛选法)

题意:输入一个数判断是不是素数,并规定2不是素数. 析:一看就很简单吧,用素数筛选法,注意的是结束条件是n<0,一开始被坑了... 不说了,直接上代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; typedef long long LL; const int maxn = 16000 + 10; int p

关于素数的快速查找——素数筛选法

利用素数筛选法进行素数的快速查找.原理很简单,素数一定是奇数,素数的倍数一定不是素数.思路如下: 预定义N表示10000,即表示查找10000以内的素数,首先定义数组prime[]对N以内的数进行标记,奇数存为1,偶数存为0,最终实现结果为素数的prime值为1,因此将prime[2]赋值为1(2是素数).之后利用for循环,对N以内的奇数进行遍历(注意for循环的条件控制),for里用if判断是否为素数(奇数),若是,执行内部嵌套的for循环判断该奇数是否为素数,若是则标记为1,若不是则pri

HDU 1164 Eddy&#39;s research I【素数筛选法】

思路:将输入的这个数分成n个素数的相乘的结果,用一个数组存储起来.之后再输出就可以了 Eddy's research I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6633    Accepted Submission(s): 3971 Problem Description Eddy's interest is very ext

POJ 2689 Prime Distance 素数筛选法应用

题目来源:POJ 2689 Prime Distance 题意:给出一个区间L R 区间内的距离最远和最近的2个素数 并且是相邻的 R-L <= 1000000 但是L和R会很大 思路:一般素数筛选法是拿一个素数 然后它的2倍3倍4倍...都不是 然后这题可以直接从2的L/2倍开始它的L/2+1倍L/2+2倍...都不是素数 首先筛选出一些素数 然后在以这些素数为基础 在L-R上在筛一次因为 R-L <= 1000000 可以左移开一个1百万的数组 #include <cstdio>

POJ 3978 Primes(素数筛选法)

题目 简单的计算A,B之间有多少个素数 只是测试数据有是负的 //AC //A和B之间有多少个素数 //数据可能有负的!!! #include<string.h> #include<stdio.h> //素数筛选法 int pri[100000+10];//1 合数, 0 素数 void Prime() { memset(pri,0,sizeof(pri)); pri[1]=pri[0]=1; for(int i=2;i<50002;i++) { if(pri[i]==0)

POJ 2262 Goldbach&#39;s Conjecture(素数筛选法)

Description In 1742, Christian Goldbach, a German amateur mathematician, sent a letter to Leonhard Euler in which he made the following conjecture: Every even number greater than 4 can be written as the sum of two odd prime numbers. For example: 8 =

数论——素数筛选法与整数的素因子分解

筛选法 求出n以内的素数,最快的应该是筛选法. 筛选法的思路是: 要求10000以内的素数,把1-10000都列出来,1不是素数,划掉:2是素数,所有2的倍数都不是素数,划掉:取出下一个幸存的数,划掉它的所有倍数:直到所有素数找完为止. 这种做法的空间复杂度是O(n),时间复杂度O(n/logn). 1 const int Max = 1000005; 2 bool prime[Max]={0};//0表示素数,1为非素数 3 4 //筛选n以内的素数 5 void getPrime(int n