短小精悍的线性筛法求素数

输入n,求n以内的所有素数

算法用两个数组存储数据:
一个是prime[],存储n以内所有的素数,其index为pi,初值为0
一个是is_prime[i],表示自然数i(i<=n)是不是质数。

void genPrime() 
{ 
        memset(isPrime,1,sizeof(isPrime)); 
        for(long i = 2 ; i < N ; i++)        
        {             
            if(isPrime[i]){ 
                prime[num_prime ++]=i; 
            }                      
            //关键处1         
            for(long j = 0 ; j < num_prime && i * prime[j] <  N ; j ++) 
            {                
                isPrime[i * prime[j]] = 0;   
                if( !(i % prime[j] ) )  //关键处2                   
                    break;            
            }         
        }   
} 

第一层遍历2到N之间的所有自然数i,看看它是不是质数,如果是,则把i放进prime数组中。

第二层循环是对所有未来的数进行筛选。对于当前正在处理的i,显然它乘以任何一个已经找到的素数的结果肯定是合数,它们将会被剔除。

 

整个算法最核心的一句是第13行:当i可以被某个已经找到的质数整除的时候,循环退出,不再进行剔除工作。

这样做的原因是:当prime[j]是i的因子的时候,设i = prime[j]*k,

       首先,我们可以肯定的说,prime[j]是i的最小质因数,这是因为第二层循环是从小到大遍历素数的;

       其次,我们可以肯定的说,i已经无需再去剔除prime[j']*i (j'>j) 形式的合数了,这是因为,

                                          prime[j']*i可以写成prime[j'] *(prime[j]*k) = prime[j]*(prime[j']*k),也就是说所有的prime[j']*i将会被将来的某个i'=prime[j']*k剔除掉,当前的i已经不需要了。

线性筛法(也称为欧拉筛法)是一种高效的素数筛选算法,其时间复杂度为 $O(n)$,能够在线性时间内筛选出 $1$ 到 $n$ 之间的所有素数。该方法的核心思想是通过遍历每个数,并将合数仅被标记一次,从而避免重复筛除,提高效率。 以下是一个使用 C++ 实现线性筛法的示例代码: ```cpp #include <iostream> #include <vector> std::vector<int> linear_sieve(int n) { std::vector<bool> is_prime(n + 1, true); // 用于标记每个数是否为素数 std::vector<int> primes; // 存储素数列表 for (int i = 2; i <= n; ++i) { if (is_prime[i]) { primes.push_back(i); // 如果i是素数,加入素数列表 } // 遍历当前已找到的素数列表 for (size_t j = 0; j < primes.size() && i * primes[j] <= n; ++j) { is_prime[i * primes[j]] = false; // 标记该合数 if (i % primes[j] == 0) { break; // 确保每个合数只被其小的质因数筛除一次 } } } return primes; // 返回n以内的所有素数 } int main() { int n; std::cout << "请输入一个正整数n:"; std::cin >> n; std::vector<int> primes = linear_sieve(n); std::cout << "1到" << n << "之间的素数有:" << std::endl; for (int prime : primes) { std::cout << prime << " "; } std::cout << std::endl; return 0; } ``` ### 代码说明: 1. **标记数组 `is_prime`**:用于记录每个数是否为素数,初始时设为 `true`。 2. **素数列表 `primes`**:存储筛选出的素数。 3. **外层循环**:从 $2$ 到 $n$ 遍历每个数 $i$。 4. **内层循环**:对于每个素数 $p$,标记 $i \times p$ 为合数;当 $i$ 能被当前素数整除时,停止内层循环以避免重复标记。 5. **输出结果**:将筛选出的素数打印出来。 ### 算法特点: - **高效性**:每个合数只会被其小的质因数筛除一次,因此时间复杂度为 $O(n)$。 - **空间复杂度**:需要一个大小为 $n+1$ 的布尔数组来标记素数,因此空间复杂度为 $O(n)$。 通过该算法,可以在较时间内处理大规模的素数筛选问题,适用于对性能要较高的场景。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值