Lesson 46 of 50 intermediate

Sieve of Eratosthenes — Finding All Primes Fast

Cross out the fakes, keep the real primes!

Open interactive version (quiz + challenge)

Real-world analogy

Imagine your teacher hands you a class list of numbers from 2 to 100 and says: 'Circle the special ones — the primes!' Instead of checking each number one by one (so slow!), you use a clever trick. Start with 2 — it's prime! Now cross out every multiple of 2 (4, 6, 8…). Move to 3 — it's still standing, so it's prime! Cross out every multiple of 3 (6, 9, 12…). Keep going. By the time you're done, only the primes are left uncrossed. That's the Sieve of Eratosthenes — a 2000-year-old shortcut that still rocks in competitive programming!

What is it?

The Sieve of Eratosthenes is an ancient algorithm that finds all prime numbers up to a given limit N. It works by repeatedly marking the multiples of each prime as composite (not prime), starting from 2. After the sieve completes, every unmarked number is prime.

Real-world relevance

Primes are the backbone of internet security — every time you shop online or send a message, encryption algorithms use huge prime numbers to keep your data safe. The sieve is also used in hash table design, random number generators, and mathematical research. In CP, it's essential for any problem involving primes or factors.

Key points

Code example

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cout << "Find all primes up to: ";
    cin >> n;

    // Create a bool array, assume all are prime
    vector<bool> is_prime(n + 1, true);
    is_prime[0] = is_prime[1] = false; // 0 and 1 are not prime

    // Sieve: cross out multiples of each prime
    for (int i = 2; i * i <= n; i++) {
        if (is_prime[i]) {
            // Start crossing from i*i (optimization!)
            for (int j = i * i; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }

    // Collect and print all primes
    vector<int> primes;
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            primes.push_back(i);
        }
    }

    cout << "Found " << primes.size() << " primes:\n";
    for (int p : primes) {
        cout << p << " ";
    }
    cout << endl;

    return 0;
}

Line-by-line walkthrough

  1. 1. We include our standard library and start the main function.
  2. 2. We ask the user for a number n — we'll find all primes up to this number.
  3. 3. We create a vector of booleans called is_prime with n+1 slots, all set to true. Each slot represents whether that number is prime.
  4. 4. We manually set is_prime[0] and is_prime[1] to false because 0 and 1 are never prime.
  5. 5. The outer loop runs i from 2 up to √n (using the condition i*i <= n). For each i, we check if it's still marked prime.
  6. 6. If i is prime, the inner loop crosses out all multiples of i starting from i*i. We set is_prime[j] = false for each multiple j.
  7. 7. After the sieve finishes, we loop through the array and collect every number still marked true into a primes vector.
  8. 8. We print how many primes were found, then print each prime separated by spaces.
  9. 9. The whole process is incredibly fast — even for n = 10,000,000, it finishes in well under a second!

Spot the bug

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n = 30;
    vector<bool> is_prime(n + 1, true);

    for (int i = 2; i * i <= n; i++) {
        if (is_prime[i]) {
            for (int j = 2 * i; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }

    // Print all primes
    for (int i = 0; i <= n; i++) {
        if (is_prime[i]) cout << i << " ";
    }
    return 0;
}
Need a hint?
Look at the printing loop. What values does i start from? Are 0 and 1 prime numbers? The sieve itself works fine, but the output includes numbers that shouldn't be called prime!
Show answer
The bug is that 0 and 1 are never marked as non-prime, so they get printed as primes! The fix is to either set is_prime[0] = is_prime[1] = false before the sieve, or start the printing loop from i = 2 instead of i = 0. Remember: 0 and 1 are not prime numbers, so we must handle them explicitly!

Explain like I'm 5

Imagine you have a big box of toy number blocks from 2 to 100. You want to find the special blocks — the ones that can't be split into smaller groups. Start with block 2 — it's special! Now take out every second block after it (4, 6, 8…) because they can all be split into groups of 2. Next, block 3 is still in the box, so it's special too! Take out every third block (6, 9, 12…). Keep doing this. When you're done fishing out blocks, the ones still sitting in the box are the special ones — the primes!

Fun fact

The Sieve of Eratosthenes was invented by the Greek mathematician Eratosthenes around 240 BC — that's over 2,200 years ago! He's also the person who first calculated the circumference of the Earth using shadows and geometry. Talk about a multi-talented genius!

Hands-on challenge

Modify the sieve to also compute the smallest prime factor (SPF) for every number up to N. Then use the SPF array to quickly factorize any number — for example, print all prime factors of 360. Bonus: solve a problem where you need to answer Q queries, each asking for the prime factorization of a number up to 1,000,000!

More resources

Open interactive version (quiz + challenge) ← Back to course: CP Zero to Hero