素數篩選法講解
阿新 • • 發佈:2018-12-21
當一個數不算大的時候,可以用普通的求素數的方法去求,但是如果一個數過大的話,就像讓求1~1000000000之間素數的個數,普通方法就不行了,這時候就需要用到素數篩選法,它的時間複雜度是O(n),儘管不算很好,但是,也算是目前為止比較快的一種方法了,它是以空間換取時間,現在的計算機,空間有的是,但是時間是非常珍貴的。
效率問題特別重要。他的原理就是標記,防止重複判斷,這樣提高了效率。就像2是素數,所有是2的倍數的肯定都不是素數,這時候標記上,接著判斷3是素數,所有是3的倍數的都肯定不是素數,這時就要標記上,以此下去,執行到根下(總數),這樣就會得到一個素數表,所有沒有被標記的都是素數,下面是具體的程式碼實現,程式碼裡面有註釋。寫的很清楚。
先來看看普通的求素數方法:
void Getprime() { prime[0] = prime[1] = false; prime[2] = true; for(int i = 2; i < MAX; i++) { bool flag = true; for(int j = 2; j <= sqrt(i); j++) //從2判斷到sqrt(i),如果i % j == 0,則i不是素數 { if(i % j == 0) { flag = false; break; } } if(flag)//不是素數就標記成false prime[i] = true; else prime[i] = false; } }
它的執行時間是非常長的,所以這時候就要引出素篩的演算法:
void Getprime() { memset(prime, true, sizeof(prime));//初始化,將prime陣列全部都初始化為true prime[0] = prime[1] = false; prime[2] = true; for(ll i = 2; i * i <= MAX; i ++)//從2開始遍歷,i * i <= MAX 就等價於 i < sqrt(MAX);但是前者更不容易出錯 { if(prime[i])//如果沒有被標記的話將它的倍數的數標記(標記就是將它賦值為false) { for(ll j = i + i; j <= MAX; j += i)//因為是從2開始的,所以j = i * i 就行了,最小的一個他的倍數的就是i * i了,不可能有比這個更小的了 prime[j] = false;//標記為false } } }
素篩的程式碼比較短,而且執行速度很快,是用了空間換了時間,不過現在來說,時間更加重要一些,所以素篩還是被廣泛運用的。
OVER!