说在前面
哈喽,大家好,你们的米饭又双叒叕回来了。接下来一段时间,我会学习一些编程基础
。为了验证学习的掌握程度,过程中会将每次的学习记录下来,会讲明白了就说明我已经学会了。作一行,爱一行,无论世界如何变化,不变的就是这些基础,这些编程过程之中的哦~
,啊哈
,哦耶~
!
如果你们有兴趣,就跟着一起学习吧。亦或是当个看官,笑笑就过去了吧!
什么是复杂度
复杂度是衡量代码运行效率的重要度量因素。在计算机中,每一个程序都是通过代码构成的,就是经过一些列的计算
,对数据进行加工
处理,最后的结果就是你所看到的成品
-- 电脑软件、手机app、网站、等等。
可见编程的核心就是要完成计算
。那对于一个计算任务得到计算结果的过程,如果这个过程复杂,计算得慢,就会大大影响到效率和体验,这便是所有编程人员都该考虑和看重的问题,你代码的复杂度
。
如何衡量复杂度
一般说来,代码在计算过程中会消耗计算时间,和计算空间。所以要衡量的就是时间复杂度
和空间复杂度
。举个例子:
生活中的十字路口有红绿灯,所有车辆依据红绿灯来通行,当大量的车通过时就会消耗每个人的时间,红绿灯越久消耗的时间越多。这便是消耗了时间
资源。
当城市规划者为这个路口设计了立交桥时,每一个方向的车辆都可以通行,不用等待红绿灯,没有时间的消耗,但是却消耗了大量的土地空间。这便是消耗了空间
资源。
计算机中也一样,要衡量的就是代码运行的时间和所占用的存储空间。输入的数据
越大,处理加工的时间就越长,可能消耗的空间也越大,所以复杂度和输入的数据有关,我们需要用数学的方式来定义它。
假设我们代码的是f(n)
,n
代表输入的数据,那么复杂度就用O(f(n))
来表示。例如: O(n)
表示计算的复杂度与输入个数n成线性相关;O(logn)
表示计算的复杂度与输入个数n成对数相关。
再则,我们记一下几个原则:
- 复杂度与具体的常量无关
O(2n)
和O(n)
表示的是相同的复杂度,O(n)
和O(n/2)
也是相同的复杂度,因为复杂度与常量无关。O(2n)
表示一段复杂度为n的代码要执行2遍,它的复杂度还是n,O(n/2)
虽然好像是少了,执行了一半的次数就可以,但是它的复杂度仍然为O(n)
- 多项复杂度相加时,取影响较大的复杂度
O(n²)+O(n)
和 O(n²)
表示的是同样的复杂度。因为O(n²)
的影响要远大于O(n)
对代码复杂度的影响,所以取O(n²)
表示复杂度即可。
- O(1)是特俗的复杂度
O(1)是特俗的复杂度,表示复杂度
与输入n无关
,一个数据进来要花5s时间,一千万个数据进来还是花5s时间。这便是O(1)
复杂度。
代码是如何影响复杂度
代码编写的好坏,程序人员的思维和解题方式是会影响运行效率的,所以才有低级工程师和高级工程师之分。我们来看一个例子。
任务:输入 a=[1,2,3,4,5],输出 [5,4,3,2,1]。
方法一:新建一个数组b,将a的数据颠倒顺序地拷贝到b,然后输出b的结果。代码如下:
const func = (a) => {
let b = []
for(let i = 0; i < a.length; i++) {
b[a.length - i - 1] = a[i]
}
return b
}
console.log( func([1, 2, 3, 4, 5]) ) // [5, 4, 3, 2, 1]
代码中的执行次数与数组a的长度有关,所以时间复杂度就是O(n)
,空间复杂度呢?因为代码中定义了一个新的数组b,它与数组a的长度一样,所以空间复杂度也是O(n)
。
方法二:定义一个缓存,直接交换a中的数据。代码如下:
const func = (a) => {
let tmp = 0
for(let i = 0; i < (a.length / 2); i++) {
tmp = a[i]
a[i] = a[a.length - i - 1]
a[a.length - i - 1] = tmp
}
return a
}
console.log( func([1, 2, 3, 4, 5]) ) // [5, 4, 3, 2, 1]
这段代码中的执行次数与为数组长度的一半
,所以时间复杂度就是O(n/2)
,根据复杂度与常量无关
原则,它的时间复杂度也是O(n)
。空间复杂度呢?代码中定义了一个tmp变量,它与数组a的长度无关,所以空间复杂度是O(1)
。
所以对于同一个问题,采用不同的计算方法,对时间和空间复杂度的影响是不一样的。每一个优秀的编码人员都必须尽可能的减少
时间和空间的损耗。
我们给出一些经验的结论,你分析代码时会简单一些:
- 顺序结构的代码,时间复杂度是
O(1)
- 二分查找,分治,时间复杂度是
O(logn)
- 一个简单for循环,时间复杂度是
O(n)
- 两个
顺序
执行的for循环,时间复杂度是O(2n)
,也就是O(n)
- 两个
嵌套
执行的for循环,时间复杂度是O(n²)
降低复杂度的必要性
很多人可能没有这么强的意识,因为他们不需要处理大量的数据,没有见到复杂度所带来的影响。我们来看一组数据。假设你的老板要你处理10万条数据,从10万个电话号码中,找到某个人:
- 如果是O(n²)的时间复杂度,计算的次数就大概是
100 亿
次左右 - 如果是O(n)的时间复杂度,计算的次数就大概是
10万
次 - 如果厉害点,在
O(log n)
的时间复杂度里完成计算,计算的次数就大概是17
次左右(log2 100000 = 16.61)
时间复杂度与 代码的设计结构
相关, 空间复杂度与 代码的数据结构
相关。要想上升到高级工程师,这些是必须打好的基础。愿我们都学以致用,乘风破浪,在代码中找到乐趣!
本文为学习《重学数据结构与算法》的学习记录!