这里每天分享一个 iOS 的新知识,快来关注我吧
前言
在开发过程中,我们始终在寻找优化代码的方法。有的时候,最强大的优化来自于看似简单的方法。
今天我们探索一个 19 世纪数学家的故事------卡尔·弗里德里希·高斯(Carl Friedrich Gauss),以及如何通过他的一个简单的算术公式显著提升 Swift 算法的性能。
高斯公式的魅力
我们先提一个需求:假设你需要计算从 1 到 n 的所有整数之和。
这是一个经典问题,并且有多种解决方法。为了演示,我编写了三个 Swift 函数来完成这一任务:
- For-In 循环
这是最直接的方法。通过迭代每个数字并累加,得到结果。
kotlin
func sumUsingForIn(n: Int) -> Int {
var sum = 0
for i in 1...n {
sum += i
}
return sum
}
- Reduce 方法
Swift 的函数式编程特性允许我们使用 reduce
方法来对范围内的数字求和。
kotlin
func sumUsingReduce(n: Int) -> Int {
return (1...n).reduce(0, +)
}
- 高斯公式
终于到了我们的重头戏------高斯公式。
年少的高斯聪明地发现从 1 到 n 的总和可以通过一个简单的等式来计算。在 Swift 中,这可以用如下方式表达:
kotlin
func sumUsingGauss(n: Int) -> Int {
return n * (n + 1) / 2
}
即:

性能测试
为了测量这些方法的速度,我使用了 Swift 的 DispatchTime
API来记录 n 为 1,000,000 时的执行时间(单位:毫秒)。
vbscript
import Foundation
func measureExecutionTime(for function: (Int) -> Int, with n: Int) {
let start = DispatchTime.now()
_ = function(n)
let end = DispatchTime.now()
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
let timeInterval = Double(nanoTime) / 1_000_000// 转换为毫秒
print("Execution time: \(timeInterval) ms")
}
// 测试每个函数
measureExecutionTime(for: sumUsingForIn, with: 1_000_000)
measureExecutionTime(for: sumUsingReduce, with: 1_000_000)
measureExecutionTime(for: sumUsingGauss, with: 1_000_000)
大家可以自行运行上面的代码,看看结果。我这里的结果为:
yaml
Execution time: 2976.284459 ms
Execution time: 168.619834 ms
Execution time: 0.019208 ms
谁是最快的?
在进入性能对比之前,我们需要了解一下 Big-O表示法 ------这一计算机科学的基本概念帮助我们评估算法的效率。
Big-O表示法描述了算法执行时间(或空间占用)如何随着输入规模的变化而增长。它以_n_为单位表示,其中_n_代表输入数据的大小。
例如:
-
O(1): 常数时间,算法性能与_n_无关。
-
O(n): 线性时间,执行时间随_n_线性增长。
-
O(n²): 平方时间,执行时间随_n_成平方增长。
理解 Big-O 至关重要,因为它帮助我们预测算法在输入规模扩大时的表现,从而更容易地为给定问题选择最有效的解决方案。
回到我们的对比,三种方法的 Big-O 分析如下:
-
For-In 循环 :每个数字都被单独处理,因此时间复杂度为O(n)。对于大的_n_,执行时间线性增长。
-
Reduce 方法 :尽管使用了函数式编程,但内部同样要遍历范围,复杂度同为O(n)。
-
高斯公式 :绝对的赢家。凭借其常数时间复杂度O(1),无论_n_的大小,它都能直接通过单个算术操作计算总和。
对于 n 为 1,000,000 的情况,这种差别显而易见。For-In 循环最慢,Reduce 方法在 swift 内部应该是被优化过的,而高斯公式只需 0.02 毫秒。
通过采用更聪明的算法,我们不仅可以实现更好的性能,还能提升可扩展性,使得高斯公式成为求和序列或类似问题的理想解决方案。
通过高斯公式,函数运行速度提升了几十万倍。
在实际应用中使用
让我们从理论转向实践,其实如果你注意观察,代码中很多场景适合使用高斯公式。
比如一个游戏应用,玩家在通过关卡时累积得分。为了显示排行榜,需要计算直到某一关卡 n 的总得分。
如下是我用于解决此问题的三种方法:
- 循环实现(基础方法)
通过迭代累加得分。
swift
func cumulativeScoreLoop(scores: [Int], upto level: Int) -> Int {
var total = 0
for i in 0..<min(level, scores.count) {
total += scores[i]
}
return total
}
- Reduce实现(函数式方法)
使用Swift的 reduce
进行求和。
swift
func cumulativeScoreReduce(scores: [Int], upto level: Int) -> Int {
return scores.prefix(level).reduce(0, +)
}
- 高斯公式实现(优化方法)
如果得分可以预测(如1, 2, 3, ...),我们可以直接计算总得分。
swift
func cumulativeScoreGaussFormula(upto level: Int) -> Int {
return (level * (level + 1)) / 2
}
结论
高斯公式的故事提醒我们,优化不一定要复杂。通过简单的数学原理,我们可以显著提升代码性能。希望这个故事能激励你在日常编程中寻找类似的优化机会。
欢迎在评论区分享你的看法或提出问题,让我们共同探索更多优化应用的可能性!
这里每天分享一个 iOS 的新知识,快来关注我吧
本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!