CS基础:算法时间复杂度
此篇为大话数据结构的笔记之一,涉及到编码的部分采用 Swift 最新版本来进行编程。序比较乱,几乎属于想到啥查啥写啥。
时间复杂度
算法分析中的一个名词,即输入到输出经过这个算法所经历的时间。
语句总的执行次数 T(n)是关于问题规模 n 的函数,劲儿分析 T(n) 随着 n 的变化情况并确定 T(n) 的数量级。T(n) = O(f(n)),这个公式表示随着问题规模 n 的增大,算法执行时间的增长率和 f(n)的增长率相同,f(n)是问题规模 n 的某个函数。这种时间复杂度的记法称为大 O 记法。
最优算法:随着规模 n 的增大,T(n)增长最慢的算法。
推导大 O 阶方法
基本原则:
- 用常数 1 取代运行时间中的所有加法常数。
- 在修改后的运行次数函数中,只保留最高阶项。
- 如果最高项存在且不是1,则去除与这个项相乘的常数。
经过三步得到的结果就是大 O 阶段。
常数阶
高斯算法:
var sum = 0,n = 100 //执行一次
sum = (1 + n) * n / 2 //执行一次
print(sum) //执行一次
包括打印结果,这个算法的运行次数函数 f(n) = 3。推导第一步,将常数3变成1。没有最高阶项,所以这个算法的复杂度为 O(1)。
增加理解,看下面这段代码:
var sum = 0,n = 100 //执行一次
sum = (1 + n) * n / 2 //执行一次
sum = (1 + n) * n / 2 //执行一次
sum = (1 + n) * n / 2 //执行一次
sum = (1 + n) * n / 2 //执行一次
sum = (1 + n) * n / 2 //执行一次
sum = (1 + n) * n / 2 //执行一次
sum = (1 + n) * n / 2 //执行一次
print(sum) //执行一次
无论 n 为多少,这两段代码的执行结果相同,区别只是固定的执行次数(循环结构除外),与 n 无关,所以复杂度还是 O(1)。
线性阶
for i in 0 ... n{
//执行时间复杂度为O(1)的算法
}
循环体中代码要执行 n 次,时间复杂度 O(n),没毛病。
对数阶
var i = 1
let n = 100
while i < n {
i *= 2
//以下执行复杂度为 O(1) 的算法步骤
}
i 每次都在加倍接近 n,2^x = n 得 x = log2n,将最高项的常数项变成1,复杂度为 O(logn)。
平方阶
var n = 100
for i in 0...n{
for j in 0...n {
//执行时间复杂度为 O(1)的算法
}
}
这段是最简单的复杂度为 O(n2)代码,在计算多重循环的算法的复杂度的时候其实就是高中数列的一些相关运算,关注算法怎么越来越接近算法结束之后的执行次数。
如:
var n = 100
for i in 0...n{
for j in i...n {
//执行时间复杂度为 O(1)的算法
}
}
这个算法的执行次数为 n2/2 + n/2,看起来很长,其实经过计算法则处理之后这段代码的复杂度为 O(n2)。