完数是等于除自身外所有正因子之和的正整数;例如6的因子1、2、3之和为6。高效判断需遍历至√n,加入i及n/i(排除n自身),避免重复与遗漏。

什么是完数?先看判断逻辑
完数(完全数)是指一个正整数,它等于**除自身以外的所有正因子之和**。比如 6 的因子是 1, 2, 3(不包括 6),而 1 + 2 + 3 == 6,所以它是完数。
关键点在于:因子必须是「能整除该数的正整数」,且**不包含自身**;求和后严格等于原数才算完数。
如何高效找因子并避免重复或遗漏
暴力遍历 1 到 n-1 虽然可行,但对大数(如 10^6 以上)太慢。更优做法是只遍历到 sqrt(n):
- 对每个能整除
n的i(i != n),把i加入因子和 - 如果
i != n / i且n / i != n,再把n / i加入(避免重复加平方根,也排除自身) - 特别注意:永远跳过
n自身,哪怕它在因子对中出现(例如n=4,i=2时n/i==2,不能加两次,也不能加4)
bool isPerfect(int n) {
if (n <= 1) return false;
int sum = 1; // 1 总是因子(n > 1 时),且不是自身
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
sum += i;
if (i != n / i && n / i != n) { // 防止加自身,也防平方根重复
sum += n / i;
}
}
}
return sum == n;
}常见错误与边界情况
写错的地方往往不是算法主干,而是边界处理:
立即学习“C++免费学习笔记(深入)”;
-
n == 1:没有真因子,和为0,不是完数 → 必须特判 -
n == 2:因子只有1,和为1 ≠ 2→ 正确返回false - 忘记排除
n自身:当n是完全平方数(如36),i == 6时n/i == 6,此时若不加n / i != n判断,会漏掉这个条件,导致误加 - 用
int i = 1开始循环却未跳过i == n:虽然i*i 保证了i (n > 1),但逻辑上仍建议显式排除自身,增强可读性
验证几个已知完数来确认实现正确
C++ 标准库不提供完数判定函数,得靠自己验证。前几个完数是 6、28、496、8128 —— 它们都很稀疏,且全部是偶数(目前未发现奇完数)。
运行以下测试可快速确认逻辑是否健壮:
for (int x : {1, 6, 28, 496, 8128, 10000}) {
std::cout << x << ": " << (isPerfect(x) ? "yes" : "no") << "\n";
}输出应为:1: no、6: yes、28: yes、496: yes、8128: yes、10000: no。如果 496 返回 no,大概率是因子求和时漏了某个因子(比如没处理 i=16 对应的 496/16=31)。
真正容易被忽略的是:因子必须是正整数,负因子不参与计算;且 0 永远不能作为除数,所以所有 % 和 / 操作前无需额外检查(因循环从 2 开始,且 n 为正整数)。











