• 如何使用用高斯公式优化 Swift 代码,让运行速度飞跃数十万倍!
  • 发布于 2个月前
  • 267 热度
    0 评论
  • Flower
  • 0 粉丝 27 篇博客
  •   
前言
在开发过程中,我们始终在寻找优化代码的方法。有的时候,最强大的优化来自于看似简单的方法。今天我们探索一个 19 世纪数学家的故事——卡尔·弗里德里希·高斯(Carl Friedrich Gauss),以及如何通过他的一个简单的算术公式显著提升 Swift 算法的性能。

高斯公式的魅力
我们先提一个需求:假设你需要计算从 1 到 n 的所有整数之和。这是一个经典问题,并且有多种解决方法。为了演示,我编写了三个 Swift 函数来完成这一任务:
For-In 循环
这是最直接的方法。通过迭代每个数字并累加,得到结果。
func sumUsingForIn(n: Int) -> Int {
   //堆代码 duidaima.com
    var sum = 0
    for i in 1...n {
        sum += i
    }
    return sum
}
Reduce 方法
Swift 的函数式编程特性允许我们使用 reduce 方法来对范围内的数字求和。
func sumUsingReduce(n: Int) -> Int {
    return (1...n).reduce(0, +)
}
高斯公式
终于到了我们的重头戏——高斯公式。年少的高斯聪明地发现从 1 到 n 的总和可以通过一个简单的等式来计算。在 Swift 中,这可以用如下方式表达:
func sumUsingGauss(n: Int) -> Int {
    return n * (n + 1) / 2
}
即:

性能测试
为了测量这些方法的速度,我使用了 Swift 的 DispatchTime API来记录 n 为 1,000,000 时的执行时间(单位:毫秒)。
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)
大家可以自行运行上面的代码,看看结果。我这里的结果为:
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 的总得分。如下是我用于解决此问题的三种方法:
循环实现(基础方法)
通过迭代累加得分。
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 进行求和。
func cumulativeScoreReduce(scores: [Int], upto level: Int) -> Int {
    return scores.prefix(level).reduce(0, +)
}
高斯公式实现(优化方法)
如果得分可以预测(如1, 2, 3, ...),我们可以直接计算总得分。
func cumulativeScoreGaussFormula(upto level: Int) -> Int {
    return (level * (level + 1)) / 2
}
结论
高斯公式的故事提醒我们,优化不一定要复杂。通过简单的数学原理,我们可以显著提升代码性能。希望这个故事能激励你在日常编程中寻找类似的优化机会。
用户评论