复杂度分析[学习笔记]

本文详细阐述了复杂度分析在算法学习中的重要性,解释了为何需要进行复杂度分析,以及介绍了大O复杂度表示法。主要内容包括时间复杂度分析的加法法则和乘法法则,以及几种常见时间复杂度实例,如O(1)、O(logn)、O(nlogn)等。此外,还探讨了空间复杂度分析,并提到了最好、最坏情况时间复杂度、平均情况时间复杂度和均摊时间复杂度的概念。通过实例解析了如何分析代码的时间复杂度,帮助读者深入理解复杂度分析的重要性及其应用。
摘要由CSDN通过智能技术生成

复杂度分析

我们都知道,数据结构和算法本身解决的是“快”和“省”的问题,即如何让代码运行得更快,如何让代码更省存储空间。所以,执行效率是算法一个非常重要的考量指标。那如何来衡量你编写的算法代码的执行效率呢?这里就要用到我们今天要讲的内容:时间、空间复杂度分析。其实,只要讲到数据结构与算法,就一定离不开时间、空间复杂度分析。

所以复杂度分析是整个算法学习的精髓,只有掌握了它,才能掌握数据结构和算法。

为什么需要复杂度分析?

你可能会有些疑惑,我把代码跑一遍,通过统计、监控,就能得到算法执行的时间和占用的内存大小。为什么还要做时间、空间复杂度分析呢?这种分析方法能比我实实在在跑一遍得到的数据更准确吗?

这种评估算法执行效率的方法当然是可以的,但是,这种统计方法有非常大的局限性。

1. 测试结果非常依赖测试环境

测试环境中硬件的不同会对测试结果有很大的影响。

2. 测试结果受数据规模的影响很大

我们以排序算法来分析,对同一个排序算法,待排序数据的有序度不一样,排序的执行时间就会有很大的差别。

所以,**我们需要一个不用具体的测试数据来测试,就可以粗略地估计算法的执行效率的方法。**这就是时间、空间复杂度分析方法。

大 O 复杂度表示法

在算法领域,同一个问题可以有不同的算法解决(比如各种排序算法),既然这样,那不同的算法之间肯定有优劣之分,如何评价呢?

最简单的评价方法是把两个算法拉过来比谁解决问题的速度快,谁的执行时间短,谁的执行次数少。

给定两个算法 A 和 B,问题规模为 n,那么执行次数分别为 CA = f(n),CB = g(n)。现在将比较两个算法的执行次数的问题转换为比较两个函数 f(n),g(n) 的问题。那比较两个函数的什么性质呢?当然是比较随着问题规模 n 增大,执行次数的增加情况,也就是 f(n),g(n) 的增长情况。

要比较两个函数的增长情况,最好的办法是比较函数的一阶导,这样最精确,但是考虑到很多时候只需要大体了解算法的优劣就可以了,所以我们就直接考察对增长速度影响最大的一项,这一项就是函数的最高阶数。为了说明最高阶数对函数增长影响最明显,我们看幅图:

增长情况

图中 4 条曲线分别表示 4 种不同的执行次数表达式,从图中可以看出,只要最高项的阶数相同,4 种表达式值受其他项的影响很小,随着 n 增大,几乎可以忽略不计,甚至可以忽略与最高项相乘的常数。

所以我们可以只考虑最高项的阶数来简化问题,达到估算的目的,大 O 符号就是用来表示这种情况的。

从维基百科上摘抄了一段关于大 O 符号的定义,如下所示:

大 O 符号(英语:Big O notation),又称为渐进符号,是用于描述函数渐近行为的数学符号。更确切地说,它是用另一个(通常更简单的)函数来描述一个函数数量级的渐近上界。在数学中,它一般用来刻画被截断的无穷级数尤其是渐近级数的剩余项;在计算机科学中,它在分析算法复杂性的方面非常有用。

通过上述分析我们可以知道 T(n = O(f(n)),其中,T(n) 就是算法的时间复杂度,f(n) 表示执行与算法优劣和问题规模有关的执行数,O() 表示一种运算符号,f(n) = 2n^2 + 1,O(f(n)) = O(n^2)。

时间复杂度分析

前面介绍了大 O 时间复杂度的由来和表示方法。现在我们来看下,如何分析一段代码的时间复杂度?

1. 只关注循环执行次数最多的一段代码

通过上面的知识,我们知道大 O 这种复杂度表示方法只是表示一种变化趋势。我们通常会忽略掉公式中的常量、低阶、系数,只需要记录一个最大阶的量级就可以了。所以,我们在分析一个算法、一段代码的时间复杂度的时候,也只关注循环执行次数最多的那一段代码就可以了。这段核心代码执行次数的 n 的量级,就是整段要分析代码的时间复杂度。

例子:

public int cal1(int n) {
   
	int sum = 0;
	for (int i = 1; i <= n; i++) {
   
		sum = sum + i;
	}
	return sum;
}

以这段代码来说,我们假设每行代码的执行时间都一样,为 t,在这个假设上的基础之上,第 2、6 行代码分别需要 1 个 t 的执行时间,第 3、4 行都运行了 n 遍,所以需要 2n * t 的执行时间,所以这段代码总的执行时间就是 (2n+2) * t,所以 T(n) = O(f(n)) = O(2n + 2) = O(n),可以看出真正对时间复杂度有影响的就是循环执行次数最多的一段代码。

2. 加法法则:总复杂度等于量级最大的那段代码的复杂度

例子:

public int cal2(int n) {
   
    int sum_1 = 0;
    int p = 1;
    for (; p < 100; ++p) {
   
      sum_1 = sum_1 + p;
    }

    int sum_2 = 0;
    int q = 1;
    for (; q < n; ++q) {
   
      sum_2 = sum_2 + q;
    }
 
    int sum_3 = 0;
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值