应使用long long类型避免溢出:long long sum_to_n(long long n) { return n

递归实现 sum_to_n 容易栈溢出
直接写 int sum_to_n(int n) { return n 看似简洁,但 n 超过几千就会触发栈溢出——每次调用都压入新栈帧,Windows 默认线程栈才 1MB,sum_to_n(10000) 就可能崩。GCC/Clang 默认不优化尾递归,哪怕你改成尾递归形式(加 acc 参数),也不保证生成跳转指令。
公式法 n * (n + 1) / 2 是唯一安全选择
数学上等差数列求和公式完全等价,且是 O(1) 时间、O(1) 空间。但要注意整数溢出:int 在 n ≈ 46340 时,n * (n + 1) 就会溢出(因为 46340×46341 ≈ 2.15e9 > INT_MAX)。实操建议:
- 用
long long接收参数和返回值,避免中间乘法溢出 - 若 n 来自用户输入,先检查是否为正整数,负数或零应直接返回 0
- 不要写
n * (n + 1) / 2而不加类型转换——int n = 100000;时,n * (n + 1)先按 int 算,已经溢出
正确写法:long long sum_to_n(long long n) { return n
递归 vs 公式法的性能差距不是“快一点”,而是“不可比”
递归法在 n=10⁵ 时要调用 10⁵ 次函数,实际耗时受栈操作、分支预测失败、缓存未命中影响;公式法就是三条 CPU 指令(乘、加、除)。实测(Clang -O2,x86-64):
立即学习“C++免费学习笔记(深入)”;
n = 1000000: 公式法:~0.3 ns(单次计算) 递归法:编译失败(栈溢出)或运行时崩溃
即使强行限制 n=1000,递归法也比公式法慢 200 倍以上。这不是编译器优化能弥补的量级差。
别用递归练手求和,真要练递归就换场景
求和是典型的“递归反模式”——问题天然有闭式解,强行递归没教学价值,反而强化错误直觉。如果目标是理解递归机制,更适合用:
-
factorial(n)(注意同样有溢出风险) - 遍历二叉树节点数(
1 + size(left) + size(right)) - 斐波那契第 n 项(但得立刻跟上记忆化或迭代改进)
真正写生产代码时,看到“从 1 加到 n”,第一反应必须是 n * (n + 1) / 2,而不是想怎么递归。











