时间与空间复杂度基础


我们如何判断一个算法的好与坏,如何对比不同的算法呢。答案就是 时间复杂度 和1空间复杂的。

1.1 时间复杂度

1.1.1 大O表示法

大O表示法,也就是算的的渐进时间复杂度

T(n) = O(f(n))

当量级增加时,我们算法执行时间的一个增长的趋势。
此处的 f(n) 代表的就是算法执行的次数
O 则代表一个正比关系

1.1.2 举例1

for (int i = 1; i <= n; i++){
    
    
	x++;
}

以上For Loop,有 N 层循环。
首先分析代码中各部分的执行次数:

  1. 首先,int i = 1 是只执行一次的。
  2. 之后是判断 i <= n;
  3. 然后是 x++;
  4. 再是 i++;
  5. 返回2,继续执行,直到 i > n;

由此可见,一共执行的次数为 1 + 3n 次,所以有 O(1 + 3n) == O(N)。
最后为什么会被简化为 O(n)呢?原因是大O表示法计算的是执行次数n接近于无限大的比例。当n接近于无限大时,这个1(常数) 和 3 对整体的影响已经无所谓了。

1.1.3 举例2

for(int i = 1; i <= n; i++){
    
    
	for(int j = 1; j <= n; j++){
    
    
		x++
	}
}

分析执行次数:
内循环:

  1. int j = 1 执行 1 次j
  2. 之后是判断 j <= n;
  3. 然后是 x++;
  4. 再是 j++;
  5. 返回2,继续执行,直到 i > n;

此时执行了 1 + 3n 次,在加上外层循环,则变为了 n + 3n2 次。在大O表示法中,我们取高阶,所以为 O( 3n2), 接着继续简化,则为 O(n2)。

1.1.4 举例3

for (int i = 1; i <= n; i++){
    
    
	x++;
}
for(int i = 1; i <= n; i++){
    
    
	for(int j = 1; j <= n; j++){
    
    
		x++
	}
}

理解了前两个例子,那么这个例子也就简单了,将两个相加就是它的时间复杂度 O(n + n2),和上一个例子一样,取高阶,则为 O(n2)。

1.1.5 举例4

int i =1;
while(i<n){
    
    
	i = i * 2;
}

这个就比较有意思,我们的 i 随着执行次数的增加而越来越接近n,此时,我们假设长执行 k 次以后就会等于n,那么则有

  • 2k = n;
  • k = logN;

这里不太好理解,需要多感受一下。当 i=1 时,i = i*2 循环k次的结果就可以化成2k
此时时间复杂度则为 O(logN)。

1.1.6 举例4

for(int i = 0; i <= n; i++){
    
    
	int i =1;
	while(i<n){
    
    
		i = i * 2;
	}
}

内层我们刚才求过了,就是 logN,外层是我们也求过了,就是 n,那么则有 O(n*logN)。

1.2 复杂度指标

  • O (Big O): 最差情况
  • Ω (Big Omega): 最好情况
  • θ (Big Theta): 一个算法的区间

1.3 空间复杂度

随着量级增加,内存空间增长的趋势
比较常见的呢,就是 O(1), O(n), O(n2)》

1.3.1 举例一

int x = 0;
int y = 0;
x++;
y++;

不管我们的x,y多大,都不会影响我们内存空间的分配,所以这是个 O(1)。

1.3.2 举例二

int[] arrArrey = new int[n]
for(int i = 0; i < n; i++){
    
    
	newArry[i] = i;
}

此时n影响着我们的空间分配。n 越大,需要分配的空间也就越大,如果数组长度为 10,则需要 10 个空间。所以此时为O(n)。

1.3.3 举例三

如果是一个2 x 2的矩阵,此时则需要n*n个空间;来分配,所以此时为O(n2)。

1.4 总结

平时比较看重的还是时间复杂度吧。因为代码的运行次数是无法通过其他途径去改变的。
为什么空间复杂度就略显弱势呢,因为氪金大佬可以升级内存啊,内存足够大,我们还管他什么内存占多占少,没有意义呀!

猜你喜欢

转载自blog.csdn.net/TakahashiRyosuke/article/details/106715368
今日推荐