Calculate the number of prime numbers in N (N) = 3) using an algorithm.
First, let's talk about the definition of prime numbers. What is a prime number? Except 1 and itself, it cannot be divisible by other natural numbers (except 0 ).
It is called a prime number (prime number); otherwise it is called a union number.
According to the definition of prime numbers, to solve this problem, I first thought of traversing each odd number from 3 to N, and then dividing by three
The odd number between the root number N can be used to calculate the number of prime numbers.
The following code is compiled:
(The code is written in C ++)
# Include
# Include
Using namespace std; const int N = 1000000; int compuPrimeN (int); int main (char argc, char * argv []) {int iTimeS = clock (); int iNum = compuPrimeN (N); int iTimeE = clock (); cout <iNum <endl; cout <"algorithm time:" <
After running:
It can be seen that the algorithm performance is not very good, and there is still much room for optimization in time.
So how should we optimize it?
First, I want to see if I can remove the multiples of 2, but later
It is found that the first remainder in the second loop is 3, so the multiples of 3 are actually calculated only once.
It filters out, and there is no need to think further.
Later I thought, in the second loop, 3 times out of the remainder. If the loop is not exceeded, 6, 9, and so on
You do not need to continue to get the remainder. Similarly, if you get the remainder of 5, you should not continue to get the remainder of 10, 15... because the remainder is obtained.
5 is not 0, so the remainder 10, 15 is certainly not 0. In other words, the remainder should not be actually a sum !!
Why? Because if it is a combination of numbers, it is bound to be able to obtain the remainder of a number smaller than its own number, that is
Previously, we wanted to filter out the numbers that do not want to get the remainder. In this way, we only need to get the remainder in the second loop.
It can be determined by a smaller prime number than its root number! However, before we calculate the prime number
Find out, so we just need to record it !!
As a result, I have rewritten the compuPrimeN () function and written 2nd algorithms:
Int compuPrimeN (int maxNum) {// algorithm 2int iNum = 1; // record the total number of prime numbers int iRecN = 1; // record the number of prime numbers in the array bool bPrimeN = true; int sqrtMaxN = (int) sqrt (maxNum); // we want to record the prime numbers smaller than sqrtMaxN. In order to make the space allocation optimal, the size is x/ln (x) * 1.2, // because scientists have found an approximate formula x/ln (x) for calculating the approximate range of prime numbers. // to avoid array out-of-bounds, add a 20% range. // note that maxNum is a special case when it is 3, because ln (root 3) is 0int * iPrime = new int [maxNum = 3? 1: (int) (float) sqrtMaxN/log (sqrtMaxN) * 1.2)]; for (int I = 3; I <= maxNum; I + = 2) {bPrimeN = true; // you only need to obtain the prime number in the remainder range. for (int j = 1; j <iRecN; j ++) {if (I % iPrime [j] = 0) {bPrimeN = false; break;} if (bPrimeN) {if (I <= sqrtMaxN) {iPrime [iRecN] = I; iRecN ++; iNum = iRecN;} elseiNum ++ ;}} delete iPrime; return iNum ;}
After running:
Look, after optimization, the algorithm's time performance is about 19 times better than the original one,
Can it be faster?
I think it works theoretically, because the previous algorithms use an idea,
Filter out multiples of 2 and 3 in advance. If we can add multiples of 5, 7, and 11
Isn't it faster to filter it out beforehand?
Why is there no 9 here, because the multiples of 9 are the multiples of 3, then? It seems
What we found is a bit similar to the idea of algorithm 2. If we can filter out
If the prime number is a multiple, isn't it possible to filter out many aggregate numbers? For this prime number + 1,
There are two situations: one is the sum of filtered out, and the other is the prime number,
Otherwise, it should be filtered out before !! In the process of filtering,
Isn't it the prime number that we want to count the unfiltered data that we encounter?
In this way, can time performance be further optimized? Yes, but in advance
Filtering out so many combinations and recording their behaviors consumes a lot
Space. This is a typical space change time !!
So the algorithm 3 I wrote was born, as follows:
Int compuPrimeN (int maxNum) {// algorithm 3 // use a bool-type large array to record. true indicates a prime number, and false indicates an even number. // calculate the number of prime numbers, so the first two can be ignored. bool * bArray = new bool [maxNum + 1]; for (int I = 2; I <= maxNum; I ++) bArray [I] = true; int iNum = 0; for (int I = 2; I <= maxNum; I ++) {// Replace the sum behind the sieve with falseif (bArray [I]) {iNum ++; for (int j = I + I; j <= maxNum; j + = I) {bArray [j] = false ;}} delete bArray; return iNum ;}
After running
Wow! I did not expect that the algorithm time could be optimized so quickly !! However, it seems like the space consumed
There are a lot of storage. It seems a waste to use only bool-type array records. Can I use 0 or 1 on each bit?
To replace records?
So I wrote the following algorithm:
Int compuPrimeN (int maxNum) {// algorithm 4 // each digit 0 or 1 is used to represent the sum and prime number respectively. // The advantage is that the maximum int size of memory space = maxNum % 8 = 0? MaxNum/8: maxNum/8 + 1; unsigned char * array = new unsigned char [size]; for (int I = 0; I <size; I ++) array [I] = 127; int iNum = 0, iBit = 0, index = 0; for (int I = 2; I <= maxNum; I ++) {index = I/8; (iBit = I % 8) = 0? IBit = 7, index --: iBit --; if (array [index] & (1 <iBit) {iNum ++; for (int j = I + I; j <= maxNum; j + = I) {index = j/8; (iBit = j % 8) = 0? IBit = 7, index --: iBit --; array [index] = array [index] & (~ (1 <iBit) ;}} delete array; return iNum ;}
Running result
Although binary computing makes the time performance slower than algorithm 3,
However, if bit is used to record the prime number or sum, the storage space is changed to the original 1/8,
The advantage is self-evident. If there is no memory space problem, so is algorithm 3.
Naturally, if you have strict requirements on memory space, algorithm 2 is the best
Preferred.
Summary:
In thinking and coding, I deeply realized the importance of algorithm optimization.
A good programmer must understand that algorithms are the soul of a program !!