題目描述 description
有乙個數n,求小於等於它的所有質數
輸入描述 input description
n 輸出描述 output description
一行,每兩個質數中有乙個空格
樣例輸入 sample input
5 樣例輸出 sample output
2 3 5
首先明確質數的概念:
乙個大於1的自然數,除了1和它本身外,不能被其他自然數整除,換句話說就是該數除了1和它本身以外不再有其他的因數;否則稱為合數。很顯然,這是求n以內所有質數的問題,對於這樣的問題,我們通常有很多種演算法。下面根據演算法的優化度介紹幾種常用的演算法。
最直觀的演算法可以從概念中得到:即外層迴圈遍歷n以內每乙個數,內層對每乙個數進行驗證;而如何驗證乙個數k是否為素數呢?根據概念,我們需要驗證k除了1和k本身外無法被(1,k)之間任意乙個數整除,那意味著內層需要做乙個[2,k-1]的迴圈遍歷。這是典型的列舉演算法設計。實際上我們可以做乙個小小的優化:若k=p*q,取m=sqrt(k),則必有p < m < q,所以在驗證k時,只需要驗證到sqrt(k)即可。
#include
#include
void printprime(int n)
else
if(n < 2)
else
int i,j;
for(i = 3;i <= n; i++)
if(j > temp)
printf("%d ",i);
}}int main()
演算法分析:使用了兩層迴圈,外層共執行n-2次,內層迴圈次數為sqrt(i)-1,平均每次執行sqrt(n/2)-1次,所以i % j的執行次數為:
(n-2)*(sqrt(n/2)-1)。取n的最高次,可以認為該演算法的時間複雜度為o(n^(3/2))。
仔細推敲上面的演算法,可以發現,雖然對內層迴圈做了優化,但是仍有繼續優化的餘地。我們知道合數一定可以分解為一系列質數之積(分解質因素),所以驗證乙個數k是否為質數,即驗證乙個數能否被所有小於k的質數整除。
#include
#include
void printprime(int n)
if(k > j)
} }int main()
演算法分析:外層迴圈仍然為n-1,但是內層迴圈改為了j,大大減少了內層迴圈的執行次數。
對於暴力列舉,無論如何優化,複雜度都在o(n^k)(其中k>1)。此時我們可以嘗試利用空間來換取時間的方法,開乙個長度為n+1的陣列primes來記錄primes[i]是否為質數,即:
primes[i] = 1 或 primes[i] = 0,如primes[2]=1;primes[3]=0。
此時根據概念i的倍數一定不是質數,對該陣列進行過濾。
#include
#include
void printprime(int n)
}for( i = 2; i<= n; i++)
return;
}int main()
此時演算法效率並沒有發生太大的變化,卻平白浪費了空間,原因是對打點過濾沒有做深入的分析,實際上還有很大的優化空間。
1.過濾時,外層迴圈實際上不需要從2到n-1,很顯然從n/2開始,就不可能整除;
2.執行primes[i]=0時有重複操作,即多次對同乙個值賦值
3.c語言中,加減法的效率要高於乘除法
//素數過濾: 2-n/2為因子過濾合數
for(i = 2; i <= n/2; i++)
}
分析到這裡,實際上還可以對演算法進行優化,比如預先對2、3、5、7、11、13的倍數進行預處理可以過濾相當大的資料。留待各位繼續分析。 求n的質因子
質因子 或質因數 在數論裡是指能整除給定正整數的質數。根據算術基本定理,不考慮排列順序的情況下,每個正整數都能夠以唯一的方式表示成它的質因數的乘積。兩個沒有共同質因子的正整數稱為互質。因為1沒有質因子,1與任何正整數 包括1本身 都是互質。只有乙個質因子的正整數為質數,質數的質因子就是它本身。將乙個...
求n個數 1 n 的質因子
求n個數 1 n 的質因子,我用到了素數篩選法的思想,例如找到素數2,2是2,4,6,8,10 的質因子,3是3,6,9,12 的質因子,然後找到素數5,若是求乙個數n的質因子,請參考 include includeint a 10001 20 b 10001 b i 表示第i個數的質因子個數,a ...
快速求n的質因子 數論
如何盡快地求出n的質因子呢?我們這裡又涉及兩個好的演算法了 第乙個 用於每次只能求出乙個數的質因子,適用於題目中給的n的個數不是很多,但是n又特別大的 includeint main if n 1 a num n for i 0 i第二個 一次求出1 n的所有數的質因子,適用於題目中給的n個數比較多...