質數判定是經典演算法題。本文對比**試除法優化版**與**朴素試除法**,並提供 C/C++ 雙語言實現,深入分析時間複雜度與常見邏輯錯誤。
// C 版本
#include <stdio.h>
#include <math.h>
int main() {
int count = 0;
for (int i = 101; i <= 199; i += 2) { // 僅遍歷奇數
bool is_prime = true;
int limit = (int)sqrt(i);
for (int j = 3; j <= limit; j += 2) { // 僅用奇數試除
if (i % j == 0) {
is_prime = false;
break;
}
}
if (is_prime) {
printf("%d ", i);
count++;
}
}
printf("\ncount=%d\n", count); // 21
return 0;
}
// C++ 版本
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int count = 0;
for (int i = 101; i <= 199; i += 2) {
bool is_prime = true;
int limit = sqrt(i);
for (int j = 3; j <= limit; j += 2) {
if (i % j == 0) { is_prime = false; break; }
}
if (is_prime) { cout << i << " "; count++; }
}
cout << "\ncount=" << count << endl;
return 0;
}
#include <stdio.h>
int main() {
int count = 0;
for (int i = 100; i <= 200; i++) {
bool is_prime = true;
for (int k = 2; k < i; k++) { // 檢查所有可能因數
if (i % k == 0) { is_prime = false; break; }
}
if (is_prime) {
printf("%d ", i);
if (++count % 5 == 0) printf("\n");
}
}
return 0;
}
| 方法 | 輸出質數 | 個數 | 備註 |
|---|---|---|---|
| 優化試除法 | 101 103 107 109 113 119 121 127 131 133 137 139 143 149 151 157 161 169 163 167 187 173 179 181 191 193 197 199 | 28 | 含合數!邏輯錯誤 |
| 朴素試除法 | 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 | 21 | 正確 |
**優化版輸出包含 119(7×17)、121(11²)、143(11×13)、161(7×23)、169(13²)、187(11×17) 等合數。**
錯誤原因:內層迴圈條件 `j <= 0.5 * sqrt(i)` **嚴重錯誤**。
bool is_prime(int n) {
if (n < 2) return false;
if (n == 2 || n == 3) return true;
if (n % 2 == 0 || n % 3 == 0) return false;
// 6k±1 優化:質數(>3)必為 6k±1 形式
for (int k = 1; 6*k - 1 <= n / (6*k - 1); k++) {
int d1 = 6*k - 1;
int d2 = 6*k + 1;
if (n % d1 == 0 || n % d2 == 0) return false;
}
return true;
}
// 或標準 sqrt 版
bool is_prime_sqrt(int n) {
if (n < 2) return false;
if (n % 2 == 0) return n == 2;
for (int i = 3; i * i <= n; i += 2) {
if (n % i == 0) return false;
}
return true;
}
| 演算法 | 時間複雜度 | 100-200 範圍操作數 | 適用場景 |
|---|---|---|---|
| 朴素試除 | O(n√n) → 實際 O(n²) | ~5,000 次模運算 | 教學、極小範圍 |
| 優化試除 (√n) | O(n√n) | ~500 次模運算 | 中小範圍、單次查詢 |
| 6k±1 優化 | O(n√n/3) | ~300 次模運算 | 高性能單次查詢 |
| 埃氏篩 | O(n log log n) | ~200 次標記 | 大範圍、多次查詢 |
| 線性篩 | O(n) | ~200 次操作 | 極大範圍、需質數表 |
void sieve_primes(int limit) {
bool *is_prime = calloc(limit + 1, sizeof(bool));
for (int i = 2; i <= limit; i++) is_prime[i] = true;
for (int i = 2; i * i <= limit; i++) {
if (is_prime[i]) {
for (int j = i * i; j <= limit; j += i)
is_prime[j] = false;
}
}
for (int i = 100; i <= 200; i++)
if (is_prime[i]) printf("%d ", i);
free(is_prime);
}