算法的目标有两种:花最少事件完成需求;花最少内存空间完成需求
相对应的度量算法性能的方法也有两种:时间复杂度分析;空间复杂度分析
时间复杂度分析
简单来说就是度量算法的执行时间
1、事后分析统计方法
这种方法就是通过计时器,计算一段程序运行的时间差
但这种方法受到很多外部因素的影响,例如计算机的硬件性能等
2、事前估算方法
求出算法所有原操作的执行次数(也称为频度),它是问题规模n的函数,用 T(n) 表示。
for(i=0;i<n;i++){ // 语句1,执行了n+1次,i=n时还执行了一次判断
for(j=0,j<n;j++){ // 语句2,执行了n*(n+1)次,n是外层循环的次数,n+1是自己执行的次数
b = 2; // 语句3,执行了n*n次
for(k=0;k<n;k++){ // 语句4,执行了n*n*(n+1)次
a = 1; // 语句5,执行了n*n*n次
}
}
}
以上面的一个循环为例,T(n)=n+1 + n*(n+1) + n*n + n*n*(n+1) + n*n*n = 2n³ + 3n² + 2n + 1
而时间复杂度"O",表示随着问题规模n增大时,算法执行时间的增长率和f(n)的增长率相同
简单来说,就是T(n)的最高阶即可
T(n) = 2n³ + 3n² + 2n + 1 = O(n³)
T(n) = 5n² + 3n = O(n²)
T(n) = 2n + 1 = O(n)
T(n) = 1 = O(1) 没有循环的算法
3、复杂的时间复杂度
上述例子中,循环体内没有对循环变量i/j/k进行操作
当循环体内对循环遍历进行了运算,看下面的例子
for(i=2; i<n;i++){
i *= 2;
}
循环中,并不能直接判断循环了多少次
所以假设循环次数为t,则2t < n,所以t = log2n
所以T(n) = O(log2n)
4、递归算法的时间复杂度
递归算法的时间复杂度的本质是要看:递归的次数 * 每次递归中的操作次数
同一道题目,同样使用递归算法,有可能时间复杂度都不同
// 以“求X的n次方”为例
// 1)for循环,时间复杂度明显为O(n)
int func1(int x, int n){
int result = 1;
for(int i=0;i<n;i++){
result = result * x;
}
return result;
}
// 2)递归法1,该方法中,递归次数=n,每次递归中的操作次数=1(1次乘法操作),所以还是O(n)
int func2(int x, int n) {
if (n == 0) {
return 1; // return 1 同样是因为0次方是等于1的
}
return func2(x, n - 1) * x;
}
// 3)递归法2
int func3(int x, int n) {
if (n == 0) {
return 1;
}
int t = function4(x, n/2); // n/2的结果是取整的
if (n % 2 == 1) {
return t*t*x;
}
return t*t;
}
这里重点分析最后一种
设递归次数为t,则n/(2t)=1,1是因为到n=1时是最后一次递归
所以t = log2n,所以时间复杂度是O(log2n)
5、常间时间复杂度的大小
O(1)< O(logn) < O(n) < O(n*logn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
空间复杂度分析
空间复杂度简单来说就是看算法占用了多少内存空间
但是由于现在的电脑内存都比较大了,对于普通的程序运行远远够用,所以很多时候都不考虑空间问题了
这里就不赘述