以前稍微總結了下求素數的辦法。但是無奈效率都不高。
今天逛了很多關於求素數的部落格,於是總結了一下最終寫出了乙個篩選法的改進演算法。
篩選法:
(一般篩選法)這種方法比較好理解,初始時,假設全部都是素數,當找到乙個素數時,顯然這個素數乘上另外乙個數之後都是合數(i是素數,那麼i*1,i*2....i*n就是合數),把這些合數都篩掉,即演算法名字的由來。
但仔細分析能發現,這種方法會造成重複篩除合數,影響效率。比如10,在i=2的時候,k=2*15篩了一次;在i=5,k=5*6 的時候又篩了一次。所以,也就有了快速線性篩法。
[cpp]view plain
copy
? /*
一般篩選法
假設全部都是素數,當找到乙個素數時,
顯然這個素數乘上另外乙個數之後都是合數。
*/#include
#include
using
namespace std;
const
int maxn = 100000;
int isprime[maxn];
void makeprime()
} } }
/*
一般篩選法
假設全部都是素數,當找到乙個素數時,
顯然這個素數乘上另外乙個數之後都是合數。
*/#include#includeusing namespace std;
const int maxn = 100000;
int isprime[maxn];
void makeprime()
} }}
線性篩選法的原理:
首先,先明確乙個條件,任何合數都能表示成一系列素數的積。
每乙個合數必有乙個最大的因子(不包括它本身),用這個因子把合數篩掉,還要另一種說啊(每個合數必有乙個最小素因子,用這個素因子篩掉合數,其實是一樣的),因為最大因子是唯一的,所以合數只會被它自己唯一的因子篩掉一次,把所有合數篩掉剩下的就全是素數了
證明略(參照:線性篩選法求素數原理】)
[cpp]view plain
copy
? /*
線性篩選法
每個合數必定有乙個最大的素因子。
所以每個合數只會被篩掉一次。
比一般篩選法效率要高一些。
*/#include
#include
using
namespace std;
const
int maxn = 10000000;
int isprime[maxn];//判斷是不是素數,1是,0不是。
int prime[maxn];//存放求得的素數。
int temp = 0;//當前已知素數的個數。
void makeprime()
for (int j = 0; j < temp&&prime[j] * i < maxn; j++)//篩去合數。
} } }
/*
線性篩選法
每個合數必定有乙個最大的素因子。
所以每個合數只會被篩掉一次。
比一般篩選法效率要高一些。
*/#include#includeusing namespace std;
const int maxn = 10000000;
int isprime[maxn];//判斷是不是素數,1是,0不是。
int prime[maxn];//存放求得的素數。
int temp = 0;//當前已知素數的個數。
void makeprime()
for (int j = 0; j < temp&&prime[j] * i < maxn; j++)//篩去合數。
}}}
然而這個方法時間複雜度和空間複雜度都不是很理想。於是出現了下面的方法。
改進的地方:
1,避開所有偶數(除2外,2單獨處理)。因為偶數至少有因子2。這樣迴圈就可以減少一半了。
2,乙個合數總可以化成若干個素數的乘積。
3,奇數x奇數(素數)=奇數。
4,每個奇數只會被篩一次。
[cpp]view plain
copy
? /*
只篩奇數的篩選法。
節省空間和時間一半。
*/#include
#include
using
namespace std;
#define maxn 10000000
int prime[maxn/2];
int isprime[maxn/2];//isprime[i]表示isprime[2*i+1],因為只處理奇數。
//【注:這裡的i為(2*i+1)】比如i=1時,表示的是2*1+1=3.同理i=2時,表示5,以此類推。
int temp = 0;
void makeprime()
long
long
int ans = i * 2 + 1;
for (int j = 1; j < temp; j++)//遍歷素數表裡小於等於ans的素數,然後把他們乘積所得的奇合數篩掉
//j從1開始因為prime[0]=2;乘積是偶數所以沒必要從0開始。j除了0之外
//所以得prime[j]都是奇素數。奇素數*奇素數=奇偶數。而且乘的都是小於
//等於ans的素數所以不會出現重複篩選的情況。
if ((ans*prime[j]) % 2==0)//若是偶數則跳過,不處理。
isprime[i*((prime[j]-1)/2)] = 0;//找到奇合數,記錄下來。
//((prime[j]-1)/2)是將prime[j]還原為只存奇數的形式。
//如5,5都是素數。那5*5=25就是奇合數對應isprime[i]的
//i=(25-1)/2=12;標記prime[12]=0;即等於說明25不是素數。
//這樣做可以節省一半的空間。
} }
}
篩選法求素數
題目 求100以內的所有素數。求素數的演算法常考,篩選法求素數不常見。定義長度為101的int陣列a 101 初始化為1。依次測試1到100的所有數字是否為素數。若i為合數,則a i 0。篩選完畢後,所有非0元素a i 所對應的數字i為素數。include using namespace std i...
篩選法求素數
篩選法求素數 質數 prime number 又稱素數。乙個 大於1的自然數 除了1和它本身外,不能被其他自然數 質數 整除,換句話說就是該數除了1和它本身以外不再有其他的因數 否則稱為合數 一 一般求素數的方法 乙個數n的因子不會超過n,但是如果我們知道數n的乙個因子a後,另乙個因子b b n a...
篩選法求素數
一 素數的定義 對於素數的定義,維基百科上給出如下一段話 素數指在大於1的自然數中,除了1和此整數自身外,無法被其他自然數整除的數。比1大但不是素數的數稱為合數。二 利用電腦程式,很容易就可以得到不太大的素數。以c語言為工具來描述常見的判斷素數的函式 int isprime int n 這個函式並不...