There is implementation of this algorithm of finding prime numbers upto n
in O(n*log(log(n))
time complexity. How can we achieve it in O(n)
time complexity?

- 70,110
- 9
- 98
- 181

- 320
- 1
- 4
- 15
-
1Why do you tag C++ and Java, as if saying "just give me the code in any of the languages"? If you ask about an algorithm don't tag any languages. If you ask a specific implementation please show us what you have done so far and tag only the appropriate language. – Lukas-T Apr 12 '20 at 08:12
2 Answers
Well, if the algorithm is O(n*log(n)) you generally can’t do better without changing the algorithm.
The complexity is O(n*log(n)). But you can trade between time and resources: By making sure you have O(log(n)) computing nodes running in parallel, it would be possible to do it in O(n).
Hope I didn’t do your homework...

- 13,939
- 5
- 50
- 79
-
-
not everything is parallelizable. not every parallelization improves complexity. the number of available CPUs is usually limited and fixed. there's cost to communications between threads, if there is such a need. etc. etc. etc. all this must be addressed specifically for a given algorithm. otherwise it's empty talk. – Will Ness Apr 12 '20 at 19:26
-
Yes, but the sieve is easily parallelizable. Since no code was given, this looked more like a theoretical question in a computer science lecture. When I studied, we could assume a large enough machine. And in practice, even O(n^2) can be much faster than O(n) even for large values of n before it turns, so what gives - it's a theoretical answer to a theoretical question. – Axel Apr 12 '20 at 19:35
-
no *fixed* amount of resources (like available cores) will ever change complexity one iota. – Will Ness Apr 12 '20 at 20:26
-
You can perform the Sieve of Eratosthenes to determine which numbers are prime in the range [2, n]
in O(n)
time as follows:
For each number
x
in the interval[2, n]
, we compute the minimum prime factor ofx
. For implementation purposes, this can easily be done by keeping an array --- sayMPF[]
--- in whichMPF[x]
represents the minimum prime factor ofx
. Initially, you should setMPF[x]
equal to zero for every integerx
. As the algorithm progresses, this table will get filled.Now we use a for-loop and iterate from
i = 2
uptoi = n
(inclusive). If we encounter a number for whichMPF[i]
equals0
, then we conclude immediately thati
is prime since it doesn't have a least prime factor. At this point, we marki
as prime by inserting it into a list, and we setMPF[i]
equal toi
. Conversely, ifMPF[i]
does not equal0
, then we know thati
is composite with minimum prime factor equal toMPF[i]
.During each iteration, after we've checked
MPF[i]
, we do the following: compute the numbery_j = i * p_j
for each prime numberp_j
less than or equal toMPF[i]
, and setMPF[y_j]
equal top_j
.
This might seem counterintuitive --- why is the runtime O(n)
if we have two nested loops? The key idea is that every value is set exactly one, so the runtime is O(n)
. This website gives a C++ implementation, which I've provided below:
const int N = 10000000;
int lp[N+1];
vector<int> pr;
for (int i=2; i<=N; ++i) {
if (lp[i] == 0) {
lp[i] = i;
pr.push_back (i);
}
for (int j=0; j<(int)pr.size() && pr[j]<=lp[i] && i*pr[j]<=N; ++j)
lp[i * pr[j]] = pr[j];
}
The array lp[]
in the implementation above is the same thing as MPF[]
that I described in my explanation. Also, pr
stores the list of prime numbers.

- 495
- 4
- 12
-
1
-
surely it does not scale though. if you don't think it's right, please provide actual run times for e.g. `n1 = 1B` and `n2 = 1.5B` so we can calculate the [Empirical orders of growth](http://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth) as `log(t2/t1) / log(1.5)`. for comparison, simple bit-packed non-segmented (contiguous) sieve of Eratosthenes on odds exhibits ~n^1.06 behavior on that range [on ideone](https://ideone.com/fapob) (that's old timings, current ideone is bound to be faster, but the orders of growth can't change much). – Will Ness Apr 12 '20 at 14:59