给定范围[低,高],请打印该范围内的所有素数?例如,如果给定范围为[10,20],则输出为11、13、17、19。
天真的方法是从低到高运行一个循环,并检查每个数字的素数。
更好的方法是使用Eratosthenes筛子预先计算最大数量的质数,然后打印范围内的所有质数。
上面的方法看起来不错,但是请考虑输入范围[50000,55000]。上述Sieve方法会预先计算2至50100的质数。这会浪费内存和时间。以下是基于分段筛的方法。
分段筛(背景)
以下是了解分段筛工作原理的基本步骤
- 使用“简单筛选”查找所有达到预定义极限的质数(在下面的代码中使用“高”的平方根),并将这些质数存储在数组“ prime []”中。基本上,我们将简单筛选称为极限,不仅找到质数,还将它们放在单独的数组prime []中。
- 创建一个数组标记[high-low + 1]。在这里,我们只需要O(n)空间,其中n是给定范围内的元素数。
- 遍历在步骤1中找到的所有素数。对于每个素数,在给定范围[low..high]中标记其倍数。
因此,与简单筛子不同,我们不检查所有小于整数high的平方根的整数倍,而仅检查在步骤1中找到的质数的倍数。我们不需要O(high)空间,我们需要O (sqrt(high)+ n)空间。
以下是上述想法的实现。
C++
// C++ program to
// print all primes in a range
// using concept of Segmented Sieve
#include
using namespace std;
// This functions finds all
// primes smaller than limit
// using simple sieve of eratosthenes.
// It stores found
// primes in vector prime[]
void simpleSieve(int limit, vector& prime)
{
bool mark[limit + 1];
memset(mark, false, sizeof(mark));
for (int i = 2; i*i <= limit; ++i)
{
if (mark[i] == false)
{
// If not marked yet, then its a prime
prime.push_back(i);
for (int j = i; j <= limit; j += i)
mark[j] = true;
}
}
}
// Finds all prime numbers
// in given range using
// segmented sieve
void primesInRange(int low, int high)
{
// Compute all primes smaller or equal to
// square root of high using simple sieve
int limit = floor(sqrt(high)) + 1;
vector prime;
simpleSieve(limit, prime);
// Count of elements in given range
int n = high - low + 1;
// Declaring boolean only for [low, high]
bool mark[n + 1];
memset(mark, false, sizeof(mark));
// Use the found primes by
// simpleSieve() to find
// primes in given range
for (int i = 0; i < prime.size(); i++)
{
// Find the minimum number
// in [low..high] that is
// a multiple of prime[i]
// (divisible by prime[i])
int loLim = floor(low / prime[i]) * prime[i];
if (loLim < low)
loLim += prime[i];
if(loLim==prime[i])
loLim += prime[i];
/* Mark multiples of prime[i]
in [low..high]:
We are marking j - low
for j, i.e. each number
in range [low, high] is
mapped to [0, high - low]
so if range is [50, 100]
marking 50 corresponds
to marking 0, marking
51 corresponds to 1 and
so on.Also if the current j
is prime don't mark
it as true.In this way we need
to allocate space only
for range */
for (int j = loLim; j <= high; j += prime[i])
mark[j - low] = true;
}
// Numbers which are not marked
// in range, are prime
for (int i = low; i <= high; i++)
if (!mark[i - low])
cout << i << " ";
}
// Driver Code
int main()
{
int low = 10, high = 20;
primesInRange(low, high);
return 0;
}
Python
# Python program to print
# print all primes in a range
# using concept of Segmented Sieve
from math import floor, sqrt
# This functions finds
# all primes smaller than limit
# using simple sieve of eratosthenes.
# It stores found
# primes in list prime[]
def simpleSieve(limit, primes):
mark = [False]*(limit+1)
for i in range(2, limit+1):
if not mark[i]:
# If not marked yet,
# then its a prime
primes.append(i)
for j in range(i, limit+1, i):
mark[j] = True
# Finds all prime numbers
# in given range using
# segmented sieve
def primesInRange(low, high):
# Comput all primes smaller
# or equal to
# square root of high
# using simple sieve
limit = floor(sqrt(high)) + 1
primes = list()
simpleSieve(limit, primes)
# Count of elements in given range
n = high - low + 1
# Declaring boolean only for
# [low, high]
mark = [False]*(n+1)
# Use the found primes by
# simpleSieve() to find
# primes in given range
for i in range(len(primes)):
# Find the minimum number
# in [low..high] that is
# a multiple of prime[i]
# (divisible by prime[i])
loLim = floor(low/primes[i]) * primes[i]
if loLim < low:
loLim += primes[i]
if loLim == primes[i]:
loLim += primes[i]
# Mark multiples of primes[i]
# in [low..high]:
# We are marking j - low for j,
# i.e. each number
# in range [low, high] is mapped
# to [0, high-low]
# so if range is [50, 100]
# marking 50 corresponds
# to marking 0, marking 51
# corresponds to 1 and
# so on. In this way we need
# to allocate space
# only for range
for j in range(loLim, high+1, primes[i]):
mark[j-low] = True
# Numbers which are not marked
# in range, are prime
for i in range(low, high+1):
if not mark[i-low]:
print(i, end=" ")
# Driver code
low = 10
high = 100
primesInRange(low, high)
Java
// Java program to print
// all primes in a range
// using concept of Segmented Sieve
import java.io.*;
import java.util.*;
class GFG {
// This function uses simple sieve of eratosthenes to
// find primes upto sqrt(high)
static void simpleSieve(int limit,
Vector prime)
{
// bound is square root of "high"
int bound = (int)Math.sqrt(limit);
boolean[] mark = new boolean[bound + 1];
for (int i = 0; i <= bound; i++)
mark[i] = true;
for (int i = 2; i * i <= bound; i++) {
if (mark[i] == true) {
for (int j = i * i; j <= bound; j += i)
mark[j] = false;
}
}
// adding primes to vector
for (int i = 2; i <= bound; i++) {
if (mark[i] == true)
prime.add(i);
}
}
// Finds all prime numbers in range low to high
// using the primes we obtained from
// simple sieve
static void segmentedSieve(int low, int high)
{
Vector prime = new Vector();
simpleSieve(high, prime); // stores primes upto
// sqrt(high) in prime
boolean[] mark = new boolean[high - low + 1];
for (int i = 0; i < mark.length; i++)
mark[i] = true;
for (int i = 0; i < prime.size(); i++) {
// find minimum number in [low...high]
// that is multiple of prime[i]
int loLim = (low / prime.get(i)) * prime.get(i);
// loLim += prime.get(i);
if (loLim < low)
loLim += prime.get(i);
if (loLim == prime.get(i))
loLim += prime.get(i);
for (int j = loLim; j <= high;
j += prime.get(i)) {
mark[j - low] = false;
}
}
// print all primes in [low...high]
for (int i = low; i <= high; i++) {
if (mark[i - low] == true)
System.out.print(i + " ");
}
}
// Driver Code
public static void main(String args[])
{
int low = 10, high = 100;
segmentedSieve(low, high);
}
}
输出
11 13 15 17 19