zoukankan      html  css  js  c++  java
  • 线性筛法求素数

    说到求素数,其实自己刚学C++那时也遇到过这种问题,如果你那时候叫我写个求1~100以内的素数的程序,我会毫不犹豫的这样写(然后被一堆大佬疯狂吊打qwq):

    #include <iostream>
    using namespace std;
    
    bool prime(int x){
        if(x<=1) return false;
        for(int i=2;i*i<=x;i++){
            if(x%i==0) return false;
        }
        return true;
    }
    int main(){  //求1~100以内的素数
        for(int i=1;i<=100;i++)
            if(prime(i)) cout << i << ' ';
        return 0;
    }
    

    其实这并不算筛法,而且时间复杂度非常高,该算法比较少用,但优点是占用空间较少
    但如果题目的数据范围一大起来,这种算法肯定挂 (这也是自己被大佬们疯狂吊打的原因吧)


    埃式筛

    第一种算法的时间复杂度太高了,下面介绍一种真正的筛法,即埃式筛,而且时间复杂度还比上面介绍的低 (这不废话吗,比上面的高那还用介绍吗?)

    #include <iostream>
    using namespace std;
    
    bool book[20005];
    int main(){  //求1~100以内的素数
        for(int i=2;i<=100;i++)
            if(!book[i]){
                for(int j=i+i;j<=100;j+=i)
                    book[j]=1;
            }
        for(int i=2;i<=100;i++)
            if(!book[i]) cout << i;
        return 0;
    }
    

    以上代码的思想是:对于不超过n的素数p,删除2p,3p,4p…,当处理完所有的数之后,还没有被删除的数就都是素数。 怎么样,是不是比第一种方法快很多? 但是,仔细分析我们就会发现,这种筛法还是存在一个问题:重复筛,比如当i为2的时候,3*i是等于6的,也就是说,当i=2的时候6就被筛掉了,但是i=3的时候,2*i也等于6,我们会发现6又被筛了一次,所以这种筛法还是达不到我们的要求。

    线性筛

    现在轮到今天的主角登场了!这就是线性筛!那么线性筛到底有什么好的呢?

    先来看看线性筛的思路:
    其实,线性筛就是埃式筛的升级版,它解决了埃式筛遗留的问题:重复筛。它让每个合数只被他的最小质因子筛一遍,它的时间复杂度接近于O(N)。(这么好的算法,简直是AK IOI必备啊)

    上代码:

    #include <iostream>
    using namespace std;
    
    bool book[20005];
    int prime[20005],pos,i,j;
    int main(){  //求1~100以内的素数
        for(i=2;i<=100;i++){
            if(!book[i]) prime[++pos]=i;
            for(j=1;j<=pos;j++){
                if(i*prime[j] > 100) break;
                book[i*prime[j]]=1;
                if(i%prime[j]==0) break;
            }
        }
        for(int i=1;i<=pos;i++)
            cout << prime[pos];
        return 0;
    }
    

    现在来逐行代码解析:
    现在来看 if(!book[i]) prime[++pos]=i; ,这段代码的作用是判断当前数是否被筛过(如果没筛过,即book[i]=0,那么这个数就是素数,所以就要往prime的尾部添加这个数字)。
    if(i*prime[j] > 100) break; 这段代码的作用是控制筛的范围
    book[i*prime[j]]=1; 则是把当前的数筛掉

    if(i%prime[j]==0) break;接下来重点解析这句话,他就是避免重复筛的关键!

    当i是prime[j]的整数倍时,说明 i * prime[j+1] 是 prime[j] 的整数倍,不需要现在筛出,因为在之后筛除过程中i * prime[j+1] 这个合数一定会被prime[j]筛除,prime[j]之后的所有素数同理,所以break跳出循环。




    参考文章:https://blog.csdn.net/FeilingGong/article/details/83660779

  • 相关阅读:
    java.text.Collat​​or
    Webservice—SOAP报文的特殊字符转义
    获取properties文件内容
    关于Webservice接口对接相关总结
    使用fastJson把对象转字符串首字母大小写问题的解决
    解决idea中启动tomcat出现控制台乱码问题
    Xshell连接VMware的linux系统
    Vmware设置Ubuntu与Windows文件夹共享
    hive学习笔记
    hive之创建桶表
  • 原文地址:https://www.cnblogs.com/Return-blog/p/12307038.html
Copyright © 2011-2022 走看看