1.算法的复杂度
算法在编写成可执行程序后,运行需要耗费时间和空间资源 因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的 即算法的时间复杂度和空间复杂度
时间复杂度主要衡量一个算法的快慢,而空间复杂度主要衡量一个算法运行所需的额外空间
在计算机发展的早期,计算机的存储容量很小,所以对空间的复杂度是很在乎,但是经过计算机行业的迅速发展,
计算机的存储容量已过达到了很高的程度,所以我们如今已经不再特别需要关注一个算法的空间复杂度了
2 大 O 的渐进表示法
大 O 符号(Big O notation)是用于描述函数渐进行为的数学符号 推导大 O 阶的方法
1.用常数 1 取代运行时间中的所以加法常数
2.在修改后的运行次数函数中,只保留最高阶的项
3.如果最高阶的项存在且不是 1,则除去与这个项目相乘的常数,得到的结果就是大 O 阶
3.时间复杂度概念
时间复杂度的定义: 在计算机科学当中,算法的时间复杂度,是一个函数,
它是定量描述了该算法的运行时间.一个算法执行所耗费的时间
从理论上来说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道, 但是我们并不需要这么做
所以我们就有了时间复杂度的分析方式:
一个算法所花费的时间与其中语句执行的次数成正比,算法中的基本操作的次数,为算法的时间复杂度
即找到某条语句与问题规模 N 之间的数学表达式,就是算出了该算法的复杂度
所以计算算法的时间复杂度,就是计算算法中的基本操作的执行次数
3.1 时间复杂度分析案例
- 例题 1:
求得 Func1 的事件复杂度,F(n)=N*N+2*N+10
随着 N 的增大,常数 10 对 F(n)的影响较小
所以这道题的时间复杂度为 O(N^2)
- 例题 2:
F(n)=2N+10
随着 N 的增大,常数 10 对 F(n)的影响较小
当 N 无限大的时候 N 和 2N 是同一个级别
最高阶为 2,则除去与这个项目相乘的常数 2
所以时间复杂度为 O(N)
- 例题 3:
这道题 M 和 N 都是 O(n)级别的
一般情况下,时间复杂度计算时未知数用的都是 N,但是也可以是其他字符
如果没有给定条件,那么这道题的复杂度是 O(M+N)
如果给定条件 M 远大于 N,则为 O(M)
如果 N 远大于 M,则为 O(N)
如果差不多大,可以为 O(M) 也可以为 O(N)
- 例题 4:
可以看出 ++count 执行了 100 次,也就是常数次
所以时间复杂度为 O(n)
- 例题 5:
冒泡排序的时间复杂度的分析,根据其思想,每次内部循环完成,都会把排好的数字放到最后
所以循环完毕后,可以看出,冒泡排序执行的数是一个等差数列求和即((N-1)+1)=*(N-1)/2=N*(N-1)/2
所以时间复杂度为 O(N^2)
- 例题 6:
二分查找,每次都会从当前数组的一半开始找,相当于每次都除以 2
最好的情况是 O(1)
最坏的情况也就是找不到或者最边上,也就是 2^x=N,即求 N 的对数
对于一个算法,我们基本上看他的最坏情况
所以二分查找的时间复杂度为 O(log2n)
- 例题 7:
斐波那契数列递归写法,是一个运行效率特别慢的写法
以 Fib(8) 为例
第一层节点个数为 2^0,第二层为 2^1,第三次 2^2 以此类推直到 2^(n-1),项数为 n,还有一侧节点是不满的,不满的节点数记录为 x
所以求斐波那契数列的操作数,F(n)=2^n-1+x
所以时间复杂度为 O(2^n)
4.算法的空间复杂度
空间复杂度是一个数学表达式,是对一个算法在运行过程中临时占用的存储空间大小的度量
空间复杂度不是程序占用了多少字节的空间,因为这个没大意义,所以空间复杂度算得是变量的个数
空间复杂度计算规则基本跟时间复杂度类似,也使用大 O 渐进表示法
函数运行所需的栈空间(存储参数,局部变量,寄存器信息)在编译期间已经确定好了,
因此空间复杂度主要通过函数在运行时显示申请的额外空间来确定
4.1 算法的时间复杂度分析案例
- 例题 1:
根据冒泡排序的思想, 总共有两个变量在循环当中
循环内部变量 j 每次循环完后会释放,然后再次创建
所以,总共就 2 个变量,空间复杂度为 O(1)
- 例题 2:
由于是计算斐波那契数列前 N 项的数组
所以每次,都会在数组后面增加一个元素,占用一个空间
所以空间复杂度就是 O(N)
- 例题 3:
递归过程中,每个栈帧的创建都会消耗一定的空间
所以计算阶乘的空间复杂度,就是计算递归深度
所以空间复杂度为 O(N)
- 例题 4:
在计算斐波那契数列递归的空间复杂度,的时候
要注意,空间是可以重复利用,不累计的,时间是一去不复返,累计的
所以空间复杂度,不是 O(2^n), 因为每次递归完最深处后,内存空间会被回收
所以,其空间复杂度就是递归的深度 O(N)


...