埃拉托斯特尼篩法是尋找 N 以內所有質數的最高效演算法之一。本範例採用 int[] 標記法(0=質數、1=合數),核心雙重迴圈僅遍歷至 sqrt(N),時間複雜度 O(N log log N),空間 O(N)。N=99999 即時完成。
public static void getPrimes(int n) {
if (n < 2 || n > 1_000_000) throw new IllegalArgumentException("n 範圍 2~1,000,000");
int[] mark = new int[n]; // 0:質數, 1:合數
mark[0] = mark[1] = 1; // 0、1 非質數
// 關鍵:外層只跑到 sqrt(n)
for (int i = 2; i * i < n; i++) {
if (mark[i] == 0) { // i 是質數
// 從 i*i 開始標記,步長 i
for (int j = i * i; j < n; j += i) {
mark[j] = 1;
}
}
}
// 輸出格式化:每行 10 個
int count = 0, perRow = 10;
System.out.println(n + " 以內的質數:");
for (int i = 0; i < n; i++) {
if (mark[i] == 0) {
if (count % perRow == 0 && count != 0) System.out.println();
System.out.print(i + "\t");
count++;
}
}
}
| 優化點 | 說明 |
|---|---|
外層上界 i*i < n | 等價 i < sqrt(n),避免浮點運算,且 i*i 可能溢位需用 long 或 i <= n/i |
內層起始 j = i*i | 小於 i*i 的倍數已被更小質數標記過(如 2*3=6 在 i=2 時已標) |
步長 j += i | 標記所有 i 的倍數 |
陣列用 byte[] 或 BitSet | 將空間從 4N bytes 降至 N bytes 或 N bits,支援更大 N |
// 使用 BitSet(JDK 內建位向量),N=1 億約 12.5 MB
BitSet isComposite = new BitSet(n);
for (int i = 2; i * i < n; i++) {
if (!isComposite.get(i)) {
for (int j = i * i; j < n; j += i) isComposite.set(j);
}
}
// 遍歷輸出
for (int i = 2; i < n; i++) if (!isComposite.get(i)) primes.add(i);
更極致可用 long[] 手寫位圖,配合輪因子跳過 2、3、5 的倍數,達到 O(N log log N / 32) 運算與 N/32 空間。