上次我们说了说时间复杂度的大小,今天我们就来分析一下这些时间复杂度
1.常数函数
n = 100 # 1 次
sum = (1 + n) *n / 2 # 1 次
print(sum) # 1 次
上述算法程序的 f(n) = 3,可能有人看到这会说那么时间复杂度就是 O(f(n)) = O(3),其实这个是错的,这个函数的时间复杂度其实是 O(1)。这个对于初学者来说是很难理解的一种结果,其实你可以把 sum = (1 + n) * n / 2 多复制几次再来看:
a = 100 # 1 次
sum = (1 + n) * n / 2 # 1 次
sum = (1 + n) * n / 2 # 1 次
sum = (1 + n) * n / 2 # 1 次
sum = (1 + n) * n / 2 # 1 次
sum = (1 + n) * n / 2 # 1 次
sum = (1 + n) * n / 2 # 1 次
print(sum) # 1 次
上述算法的 f(n) = 8,事实上你可以发现无论 n 为多少,上述两段代码就是运行 3 次和运行 8 次的区别。这种与数据的规模大小 n 无关,执行时间恒定的算法我们就叫它具有 O(1) 的时间复杂度。不管这个常数是多少,我们都记作是 O(1),而不是 O(3) 或者是 O(8)。
2.对数函数
cnt = 1
while cnt < n:
cnt *= 2 # O(1)
上面的算法程序的时间复杂度就是 O(logn),这个是怎么算出来的呢?其实很简单:上述的代码可以解释成 cnt 乘以多少个 2 以后才能大于等于 n,我们假设个数是 x,也就是求 2^x = n,即 x = log2n,所以这个循环的时间复杂度就是 O(logn)。
最后呢,我们来看看下面的这个例子,借助这段代码来详细的说一下我们如何对其时间复杂度进行详细的分析:
a = 1
b = 2
c = 3
for i in range(n):
for j in range(n):
x = i * i
y = j * j
z = i * j
for k in range(n):
u = a * k + b
v = c * c
d = 4
上面的代码没有任何意义,甚至不是一个可运行的代码,我只是用来说明你在以后如何对代码进行执行分析,关于代码本身可不可以运行,就不需要你在这关心了。
上面的代码其实我们要分的话可以分成 4 部分:第 1 部分是 a,b,c 这 3 个赋值语句,执行次数也就是 3 次;第二部分是 3n^2,因为是循环结构,里面有 x,y,z 这 3 个赋值语句,每个语句执行了 n^2 次;
第 3 部分是 2n,因为里面是 2 个赋值语句,每条语句被执行了 n 次;最后第 4 部分是常数 1,只有 d 这么 1 条赋值语句。所以我们得到的 T(n
) = 3+3n^2 +2n+1 = 3n^2+2n+4,看到指数项,我们自然的发现是 n^2 做主导,当 n 增大时,后面两项可以忽略掉,所以这个代码片段的数量级就是 O(n^2)。