[数据结构](一)时间复杂度

时间复杂度的解释与例题

声明:本人也在学习过程中,难免出现错误,所以如果大家发现错误,请不吝赐教,谢谢指正。

在数据结构考研大纲的基础知识中,对算法的时间复杂度的计算一直是考察的重点。这一部分如果说简单,但是又容易出错;如果说难,又是有规律可循的。因此,只要按照特定的步骤对程序进行逐步分析,就能准确无误的得到答案。

让我们先来看一看时间复杂度的定义。

01定义

时间复杂度是对算法效率的衡量标准,这是对其定性的描述。对于其定量描述,要引入以下概念:

频度: 一个语句的频度是指该语句在算法中被执行的次数。

比如下列程序中:

# 例
a = 0
for i in range(10):
    a += i

其中 a += i 语句的被执行次数是10,频度也就是10。

我们设算法中所有语句的执行次数之和为 T ( n ) T(n) T(n) n n n 为问题规模,那么可以知道,算法最深层次的语句(例如例中的a+=1)的执行次数与 T ( n ) T(n) T(n)是同数量级的,计算 T ( n ) T(n) T(n) 时比较复杂,所以我们可以通过最深层次语句的频度 f ( n ) f(n) f(n)来衡量算法的时间复杂度,记为:
T ( n ) = O ( f ( n ) ) T(n) = O(f(n)) T(n)=O(f(n))
其中, O O O 的含义是 T ( n ) T(n) T(n) 的数量级,表达的意思是, T ( n ) T(n) T(n) 的数量级是 f ( n ) f(n) f(n) 的函数,即与最深层次的语句频度有关。

由此一来,我们在计算的时候就有了目的,只要计算出 f ( n ) f(n) f(n),就相当于找到了时间复杂度。

02分类以及规则

021分类

虽然对于一个算法来说,程序的执行步骤是确定的,但是面对不同的输入数据,时间复杂度也会有所区别,因此按照结果的不同,可以将复杂度分为以下几类:

  1. 最坏时间复杂度
  2. 平均时间复杂度
  3. 最好时间复杂度

举一个例子,在后序查找算法中,如果目标元素在最后一个位置,那么第一次比较就可以得到答案,此时底层移位语句的执行次数 f ( n ) f(n) f(n)为常数,则时间复杂度为 O ( 1 ) O(1) O(1);如果目标元素在第一个位置,那么底层移语句执行次数为 n n n ,则时间复杂度为 O ( n ) O(n) O(n)

为了衡量一个算法的整体效率,我们一般使用最坏时间复杂度来表示算法的效率下限。如果没有特殊说明,时间复杂度指的都是最坏时间复杂度。

022规则

加法规则

当要衡量的算法由几个底层语句并列时,我们遵守加法规则,即:

T ( n ) = T 1 ( n ) + T 2 ( n ) = O ( g ( n ) ) + O ( f ( n ) ) = O ( max ⁡ ( g ( n ) , f ( n ) ) ) T(n) = T_1(n)+T_2(n) = O(g(n))+O(f(n)) = O(\max(g(n),f(n))) T(n)=T1(n)+T2(n)=O(g(n))+O(f(n))=O(max(g(n),f(n)))

乘法规则

当算法的底层语句出现与上层的嵌套时,遵守乘法规则,即:

T ( n ) = T 1 ( n ) × T 2 ( n ) = O ( g ( n ) ) × O ( f ( n ) ) = O ( g ( n ) × f ( n ) ) T(n) = T_1(n)\times T_2(n) = O(g(n))\times O(f(n)) = O(g(n)\times f(n)) T(n)=T1(n)×T2(n)=O(g(n))×O(f(n))=O(g(n)×f(n))

常见的时间复杂度的比较

O ( 1 ) < O ( log ⁡ 2 n ) < O ( n ) < O ( n log ⁡ 2 n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)<O(\log_2n)<O(n)<O(n\log_2n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n) O(1)<O(log2n)<O(n)<O(nlog2n)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)

03例题解析

开头已经说过,时间复杂度这一块虽然算起来很复杂,但是计算有章法,只要按照步骤计算,总能得出正确答案,接下来把我总结的方法结合几个例题进行详细解释。

方法:

一般的程序都是套在循环当中的,所以我们先设置一个变量 t t t 来存放循环的次数,其次,程序中会有一个基本计数单位 i i i ,每一次循环都会判断计数单位 i i i 是否满足特定条件,最底层程序的执行次数其实就是循环判断条件满足的次数,最终我们根据循环次数 t t t 与计数单位 i i i 的关系,代入循环条件,就能得到程序的时间复杂度。

请看下列例题的详细解释。

例1

n n n 是描述问题规模的非负整数,那么下列程序片段的时间复杂度是多少?

x = 2;
while(x<n/2)
    x = 2*x;

解:

t t t 为循环执行次数,程序中的 x x x 为基本计数单位,可以得到下表:

tx
12
24
38
416

[注意,这里的 x x x 值是对应第 t t t 次的循环判断语句结束后的状态,并未执行底层语句]

经过几次推理,我们可以得到 t t t x x x 的关系为: x = 2 t x = 2^t x=2t

根据我们的循环条件 x < n / 2 x<n/2 x<n/2 ,有 2 t < n / 2 2^t<n/2 2t<n/2

则可以得到 t < log ⁡ 2 ( n / 2 ) = log ⁡ 2 n − 1 < log ⁡ 2 n t<\log_2(n/2) = \log_2n-1<\log_2n t<log2(n/2)=log2n1<log2n

因此该程序片段的时间复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n)

例2

下列函数的时间复杂度是多少?

int func(int n){
    int i = 0,sum = 0;
    while(sum<n)
        sum += ++i;
    return i;
}

解:

设循环次数为 t t t ,基本计数单位是 s u m sum sum,但是 s u m sum sum i i i 有关,所以我们将 i i i 也考虑在内,方便计算,于是可以得到下表

tisum
101
211+2 = 3
321+2+3 = 6
431+2+3+4 = 10

好了,我们可以看出, s u m sum sum t t t 的关系为 s u m = t ( 1 + t ) 2 sum = \frac{t(1+t)}{2} sum=2t(1+t) ,则由判断条件中 s u m < n sum<n sum<n 可以得到 t ( t + 1 ) 2 < n \frac{t(t+1)}{2}<n 2t(t+1)<n ,则 t t t n n n 的关系为 t < 2 n t<\sqrt{2n} t<2n ,因为时间复杂度是一个数量级,所以去掉系数此函数的时间复杂度为 O ( n ) O(\sqrt{n}) O(n )

例3

下列程序段的时间复杂度是多少?

count = 0;
for(k=1;k<n;k*=2)
    for(j=1;j<n;j++)
        count++

解:

这道题的最底层语句是两层循环嵌套实现的,很明显要用乘法规则计算,我们可以分开算。

对于最外层,设执行次数为 t 1 t_1 t1 ,基本计数单位是 k k k ,则可得下表:

t 1 t1 t1 k k k
11
22
34
48

则可以得到 k = 2 t 1 − 1 < n k = 2^{t_1-1} <n k=2t11<n ,即 t 1 < log ⁡ 2 n + 1 t_1<\log_2n+1 t1<log2n+1 ,去掉杂项,则最外层的时间复杂度为 O ( log ⁡ 2 n ) O(\log_2n) O(log2n)

对于最内层,可以直观的看出时间复杂度为 O ( n ) O(n) O(n).

所以由乘法规则有,整个程序的时间复杂度为 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n)

04总结

这一块知识考察的很单一,所以很有可能用其他的方式综合考察,比如说搭配排序,查找,甚至一些更复杂的存储结构的增删改查。但是万变不离其宗,只要抓住最主要的那一个点,分析清楚最底层语句的执行逻辑,就能很快的解出答案。

作者:Ap01lo
首发网站:https://ap01lo.github.io/
转载请注明出处

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值