is_prime函数通过特判n
is_prime 快速判断单个数是否为素数对单个整数做素性判断,最直接的方式是试除法:检查从 2 到 √n 是否有能整除 n 的数。但要注意几个关键点:
n (0、1 不是素数),n == 2 直接返回 true
n == 2,其余偶数直接返回 false,避免一半无谓循环i * i 而非 i ,避免浮点误差和 sqrt 调用开销
bool is_prime(int n) {
if (n < 2) return false;
if (n == 2) return true;
if (n % 2 == 0) return false;
for (int i = 3; i * i <= n; i += 2) {
if (n % i == 0) return false;
}
return true;
}std::vector 做埃氏筛就够了当需要批量判断 [2, N] 内所有数是否为素数,埃拉托斯特尼筛法(埃氏筛)简单可靠。对 N ≤ 10⁶,用 std::vector 即可,空间紧凑且缓存友好:
true,is_prime[0] 和 is_prime[1] 设为 false
i * i 开始标记,因为更小的倍数已被更小的质数筛过vector 或 bitset(除非 N > 10⁷),前者浪费空间,后者在小规模下无明显优势且语法冗余std::vectorsieve(int n) { std::vector is_prime(n + 1, true); is_prime[0] = is_prime[1] = false; for (int i = 2; i * i <= n; ++i) { if (is_prime[i]) { for (int j = i * i; j <= n; j += i) { is_prime[j] = false; } } } return is_prime; }
埃氏筛时间复杂度是 O(N log log N),而线性筛能做到严格 O(N),关键在于每个合数只被其最小质因子筛一次。它适合 N ≥ 10⁷ 且内存允许的情况:
primes 和一个最小质因子数组 min_prime(或仅用 is_prime + 额外逻辑)i % primes[j] == 0,立刻 break —— 这保证了后续更大的质数不会用来筛 i * primes[j],否则最小质因子就不是 primes[j]
primes 容量预留足够(π(N) ≈ N / ln N)std::vectorlinear_sieve(int n) { std::vector is_prime(n + 1, true); std::vector primes; for (int i = 2; i <= n; ++i) { if (is_prime[i]) primes.push_back(i); for (int p : primes) { if (i * p > n) break; is_prime[i * p] = false; if (i % p == 0) break; } } return primes; }
is_prime 判断大量数字如果问题本质是「查询多

is_prime 是 O(√n),最坏情况可能超时(例如全为 10⁹ 附近的大数)。这时应:
max_n
max_n ≤ 10⁶,直接筛出 [2, max_n] 的素数表,O(1) 查询max_n > 10⁶ 但查询数不多(如 ≤ 10⁴),仍可用优化版 is_prime,但务必加 6k±1 优化(跳过所有 2、3 的倍数)很多人卡在“以为单次试除够快”,实际数据一多,缓存不友好 + 重复开方 + 偶数未剪枝,性能会断崖式下跌。