目录
一,引言
算法在编成一个可执行程序后,在运行时需要消耗时间资源和空间资源。由此衡量一个算法的好坏,是从时间和空间上进行衡量的。由此引出分别衡量时间和空间的时间复杂度和空间复杂度。
时间复杂度用来衡量算法执行所需要的时间。空间复杂度用来衡量算法执行时所要额外的空间。
二,时间复杂度
1,时间复杂度的概念
算法的++时间复杂度++ 本质上是一个函数,定量的描述了算法执行所要消耗的时间。算法中的++基本操作的执行次数++,就是算法的时间复杂度。
2,计算时间复杂度
_1,运算规则

上面的基本操作的执行次数为:
F(N)=N^2+2*N+10
此时再通过++大O的渐进表示法++对上述式子进行处理:
大O符号:描述函数渐进行为的数学符号
步骤:
1,用常数1取代公式中的所有加法常数
2,只保留最高阶项
3,去除与最高阶项的相乘的系数
通过上述步骤后的最终时间复杂度为: O(N^2)
其中有些算法的时间复杂度存在最好,最坏,和平均的情况:
最坏情况:算法的最大运行次数(上界)
平均运行情况:算法的预期运行次数,或者将每种可能相加,最后除以N
最好情况:算法的最小运行次数(下界)
例如:在一个长度为N的数组中查找值为x的数
最好情况:1次
最坏情况:N次
平均情况:(1+2+3+......+N)/N = (N+1)/2
实际情况中使用最坏的情况,所以在数组中查找x的时间复杂度为:O(N)
_2运用实例:
常数O(1)类型:
1,

2,

N^2类型:


调用了N次,每次执行循环N,N-1,N-2......1,所以总共执行次数:1+2+3+......+N = N*(N+1)/2
故时间复杂度为:O(N^2);
log(2)n类型:
1,循环中 i<n;i *=2

2,二分查找


查找时的变化:
N/2 N/4 N/8 N/16 ......
最坏的情况:当数组中只剩下一个数或找不到时最坏
N/2/2/2/2...... = 1 -- N/(2^x) = 1
时间复杂度为2出现的次数
2^x = N x = log(2)N
故时间复杂度为O(log(2)N)
2^N类型:


累计调用的结果为:2^(N-1)-1
实际次数要比求和的值小一点,原因:

由上图可知:右边先比左边先到底,所以实际会小一点
第二种方法:

总结一下,常见的时间复杂度共有以下几种情况:

三,空间复杂度
1,空间复杂度的概念
++空间复杂度++ 也是一个数学表达式,描述一个算法执行时需要++临时额外****占用的内存空间大小++。空间复杂度计算的是变量的个数。
2,空间复杂度的计算
空间复杂度的计算的关键就是计算++额外新增加的变量个数++。
计算规则同样遵循大O渐进表示法:
1,用常数1取代公式中的所有加法常数
2,只保留最高阶项
3,去除与最高阶项的相乘的系数
冒泡排序:

再这个函数中只有end,exchange,i三个变量,所以空间复杂度就是:O(1)
其中形参:a,n不计入其中。
轮转数组:

核心思路:创建一个新数组,先将5,6,7拷贝到新数组当中,再将1,2,3,4拷贝到新数组当中,最后将tmp中的元素重新拷贝到nums当中

代码实现:

由于拷贝相当于将原数组中的数全部遍历一遍,所以此算法的时间复杂度为:O(N)
由于创建了一个元素个数为N的新数组,所以共创建了N个新变量,所以算法的空间复杂度为O(N)
阶乘递归的空间复杂度:

每次函数调用会开辟一个++函数栈帧++,总共调用了N次,所以总共开辟了N个栈帧,所以空间复杂度为: O(N)
常见的空间复杂度只有三个为:O(1) O(N) O(N^2)
四,时间复杂度OJ练习:
1,

解法1:先求和再减去数组元素

解法2:异或

2,

解法一:暴力求解

轮转次数:
最坏的情况是:k%numsSize=numsSize-1 --轮转n-1次
最好的情况是:k%numsSize = 0; --无需轮转
每次轮转时,要将数组中的numsSize-1个数向后整体移动一位
所以时间复杂度为:O( (N-1)*(N-1) ) = O(N^2)
时间复杂度过高,导致超出时间限制
解法2:逆置三次

代码实现:

相当于将数组当中的元素遍历了两次,所以逆置三次的时间复杂度为:O(N)
补充内容:
clock函数
头文件:#include <time.h>
核心功能:测试程序所消耗的处理器时间
返回值:返回值类型为clock_t,为一个整数,单位为毫秒
注意:下面使用int来接收也可以,方便使用%d打印。
