# Sieve of Eratosthnes in C++

designed to identify all prime numbers within a defined range or up to a specified limit 'n'. It is named after the ancient Greek mathematician Eratosthenes. This algorithm offers a systematic approach to sieving out non-prime numbers, making it an invaluable tool in number theory and various computational applications.

The algorithm begins by creating a list of numbers from 2 to 'n' and initially assuming that all of them are prime. After that, it systematically marks the multiples of each prime number, starting with 2, which is the smallest prime. As it progresses, the algorithm incrementally uncovers the prime numbers within the given range.

The key insight driving the Sieve of Eratosthenes is that any multiple of a prime number is itself composite (non-prime). Therefore, the algorithm efficiently filters out non-prime candidates by successively marking these multiples. The process continues until the square root of 'n' is reached, after which the remaining unmarked numbers are confirmed as prime.

Initialization: Create a boolean array or vector of size 'n+1', where each element represents a number from 0 to 'n'. Initially, all elements are set to "true" to assume that all numbers are prime.

Marking Non-Primes: Start with the first prime number, which is 2. Mark all multiples of 2 as non-prime by setting their corresponding array elements to "false". This step eliminates numbers like 4, 6, 8, 10, etc., from the list of potential prime numbers.

Find the Next Unmarked Number: After marking multiples of 2, find the next unmarked number greater than 2. This number will be the next prime number. it's 3 in the first iteration.

Repeat the Process: Continue the process by marking all multiples of the next prime number (3 in this case) as non-prime. In the next iteration, find the next unmarked number, which will be the next prime number (in this case 5), and repeat the process. Continue this iteration until the square root of 'n' is reached.

Result: Once the process is complete, all unmarked numbers in the array are prime numbers. The algorithm has sieved out the non-prime numbers, leaving behind only the primes.

The Sieve of Eratosthenes is highly efficient for finding prime numbers, especially when dealing with large ranges of numbers because it avoids the need for expensive prime testing operations for each number individually. Instead, it systematically eliminates multiples of known primes to identify new primes.

### Program-1:

It is C++ code implementation of the Sieve of Eratosthenes algorithm to find all prime numbers up to a given limit 'n'. This code uses the basic approach with a boolean vector to mark prime and non-prime numbers:

Output

```Enter the limit (n): 20
Prime numbers up to 20 are: 2, 3, 5, 7, 11, 13, 17, 19
```

Explanation:

• The program begins with the inclusion of necessary libraries: iostream for input/output and vector to use a dynamic array to store prime numbers.
• The sieveOfEratosthenes function is defined to implement the Sieve of Eratosthenes algorithm. It takes an integer n as input, representing the upper limit to find prime numbers up to.

Inside the sieveOfEratosthenes function:

• A boolean vector isPrime is created with a size of n + 1. Each element of this vector represents a number from 0 to n. Initially, all elements are set to true, assuming that all numbers are prime.
• The elements at indices 0 and 1 in the isPrime vector are explicitly set to false because 0 and 1 are not prime numbers.
• The main part of the algorithm starts with a for loop that iterates from 2 to the square root of n (p * p <= n). This loop is responsible for finding prime numbers.

Inside the loop:

• If isPrime[p] is true, it means that p is a prime number.
• After that, we enter another loop that starts from p * p and increments by p. This inner loop marks all multiples of p as non-prime by setting the corresponding elements in the isPrime vector to false. It eliminates numbers that are multiples of known prime numbers.
• After the outer loop completes, the isPrime vector contains true for prime numbers and false for non-prime numbers.
• Finally, the code prints out the prime numbers up to n in a human-readable format. A first variable is used to handle the formatting of the output (adding commas between prime numbers).

In the main function:

• The user is prompted to enter the limit (n) for finding prime numbers.
• If n is less than 2, a message is displayed indicating that there are no prime numbers in the specified range.
• Otherwise, the sieveOfEratosthenes function is called to find and print the prime numbers up to n.

Complexity Analysis:

Time Complexity:

Outer Loop: The outer loop in the sieveOfEratosthenes function iterates from 2 to the square root of 'n'. In Big O notation, this part has a time complexity of O(sqrt(n)). It is because we only need to consider prime numbers up to the square root of 'n' to eliminate multiples.

Inner Loop: Inside the outer loop, there's an inner loop that marks the multiples of the current prime number 'p' as non-prime. The inner loop runs approximately 'n/p' times for each prime 'p'. As we progress, 'p' becomes larger, and the number of multiples it marks decreases. So, the sum of the iterations for all primes is roughly:

n/2 + n/3 + n/4 + ... + n/p

This series converges to n * (1/2 + 1/3 + 1/4 + ... + 1/p), which is approximately n * log(log(n)) in the worst case.

Total Time Complexity: Combining the time complexities of the outer and inner loops, the overall time complexity of the Sieve of Eratosthenes is approximately O(sqrt(n) * log(log(n))).

Space Complexity:

The space complexity of the Sieve of Eratosthenes is determined by the space required to store the boolean vector isPrime, which has 'n + 1' elements.

Therefore, the space complexity of the algorithm is O(n).

### Program-2:

Another approach to implementing the Sieve of Eratosthenes algorithm in C++ is to use a more memory-efficient version that requires less space. This method uses a bitset instead of a boolean vector to reduce memory usage. Here's a C++ implementation using this approach:

Output

```Enter the limit (n): 50
Prime numbers up to 50 are: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47
```

Explanation:

• The program begins with including necessary libraries: iostream for input/output operations, bitset for memory-efficient storage of prime information, and cmath for mathematical functions.
• The sieveOfEratosthenes function is defined to implement the Sieve of Eratosthenes algorithm. It takes an integer n as input, representing the upper limit to find prime numbers up to.

Inside the sieveOfEratosthenes function:

• There is a check to handle a special case where 'n' is less than 2. If 'n' is less than 2, it means there are no prime numbers in the specified range, so a message is displayed, and the function returns early.
• A bitset named isPrime is created with a size of 1000001. This bitset is used to efficiently mark numbers as prime (1) or non-prime (0). It provides a memory-efficient alternative to boolean vectors.
• All numbers in the isPrime bitset are initialized as prime (set to 1) because we start with the assumption that all numbers are prime. We later mark non-prime numbers as 0.
• The numbers 0 and 1 are explicitly marked as non-prime (set to 0) because they are not prime numbers.
• After that, the algorithm proceeds to mark non-prime numbers by starting with the first prime number, which is 2.
• The core of the Sieve of Eratosthenes algorithm is the part inside the for loop:
• The outer loop iterates from 2 to the square root of 'n' (p * p <= n). This loop is responsible for finding prime numbers.

Inside the loop:

• If isPrime[p] is true, it means that 'p' is a prime number.
• The inner loop starts from p * p and increments by 'p'. It marks all multiples of 'p' as non-prime by setting the corresponding bits in the bitset to 0. It eliminates numbers that are multiples of known prime numbers.
• After the outer loop completes, the bitset isPrime contains 1s for prime numbers and 0s for non-prime numbers.
• Finally, the code prints out the prime numbers up to 'n' in a human-readable format. A first variable is used to handle the formatting of the output (adding commas between prime numbers).

In the main function:

• The user is prompted to enter the limit (n) for finding prime numbers.
• The sieveOfEratosthenes function is called to find and print the prime numbers up to 'n'.
• This implementation is memory-efficient due to the use of the bitset and retains the time complexity of approximately O(sqrt(n) * log(log(n))), making it suitable for finding prime numbers within a given range.

Complexity Analysis:

Time Complexity:

Initialization phase involves setting up a bitset of size 1000001, representing numbers from 0 to 'n'. This initialization step takes O(n) time but can be considered constant for practical purposes due to the fixed size bitset.

The core of the algorithm is the outer loop, responsible for prime detection. It iterates approximately sqrt(n) times (O(sqrt(n))) to identify primes. It is because there's no need to consider numbers larger than the square root of 'n' when looking for primes.

The inner loop marks multiples of prime numbers as non-prime, and it runs roughly n * log(log(n)) times in total. This complexity arises because the number of iterations decreases as prime numbers are discovered, converging to n * log(log(n)) in the worst case.

The total time complexity can be expressed as O(n + sqrt(n) + n * log(log(n))), encompassing initialization, prime detection, and marking multiples. In practice, the inner loop's contribution, n * log(log(n)), dominates the complexity. This detailed breakdown clarifies how time is distributed across various algorithmic steps, facilitating a comprehensive understanding of its efficiency.

Space Complexity:

Bitset for Prime Marking:

• The bitset named isPrime is used to mark numbers as prime (1) or non-prime (0).
• The size of the bitset is fixed at 1000001, which is sufficiently large to handle numbers up to 'n'.
• Therefore, the space complexity for the bitset is O(1000001), which can be approximated to O(1), as it's a constant-size data structure.

There are some additional variables used in the code, such as integer variables (n, p, i, first, etc.), which occupy a constant amount of memory.

So, the space complexity for these variables is O(1).