01-时间复杂度和空间复杂度
时间复杂度和空间复杂度介绍
大O时间复杂度表示法
我们先来看两个例子:
我们把执行一行代码的时间标为 1
例子一:
int cal(int n) {
int sum = 0; // 1
int i = 1; // 1
for (; i <= n; ++i) { // n
sum = sum + i; // n
}
return sum;// 1
}
对上述执行时间进行相加
2n+3
个执行时间
例子二:
int cal(int n) {
int sum = 0; // 1
int i = 1; // 1
int j = 1; // 1
for (; i <= n; ++i) { // n
j = 1; // n
for (; j <= n; ++j) { // n*n
sum = sum + i * j; // n*n
}
}
}
我们对上述执行时间进行相加
2n^2+2n+3
个执行时间
我们现在看完两个例子了
现在我们来分析一下,可以得出这样一个结论
所有代码的执行时间T(n)与每行代码的执行次数n成正比
最后,我们可以得到一个结论
T(n)=O(f(n))
-
T(n)
: 是代码的执行时间 -
f(n)
:表示每行代码的执行次数 -
O()
:表示代码的执行时间与每行代码的执行次数成正比
上述公式也就是大O时间复杂度表示法
大O时间复杂度实际上并不是具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以也叫做渐近时间复杂度,简称时间复杂度
所以我们来看下上面的两个例子
第一个例子的大O时间复杂度: O(2n+3);
第二个例子的大O时间复杂度:O(2n^2+2n+3);
时间复杂度分析
我们该如何去分析时间复杂度呢?
我们来看接下来的方法
注意:分析的时候,忽略掉 公式中的
常量
,低阶
,系数
,这并不会影响变化趋势,只需要记录最大阶的量级就行了
-
只关注循环执行次数最多的一段代码
int cal(int n) { int sum = 0; int i = 1; for (; i <= n; ++i) { //n sum = sum + i; // n } return sum; }
在这段代码中,执行次数最多的是那个for循环执行的,需要执行n次
那么它的时间复杂度为 O(n);
-
加法法则:总复杂度等于量级最大的那段代码的复杂度
int cal(int n) { int sum_1 = 0; // 1 int p = 1; // 1 for (; p < 100; ++p) { // 100 sum_1 = sum_1 + p; //100 } int sum_2 = 0; // 1 int q = 1; // 1 for (; q < n; ++q) { // n sum_2 = sum_2 + q; //n } int sum_3 = 0; //1 int i = 1; //1 int j = 1; //1 for (; i <= n; ++i) {// n j = 1; //1 for (; j <= n; ++j) { //n*n sum_3 = sum_3 + i * j;//n*n } } return sum_1 + sum_2 + sum_3;//n }
这段代码中
第二个循环代码的时间复杂度为 O(n)第三个循环代码的时间复杂度为O(n^2);
我们取最大量级的时间复杂度,.那就是O(n^2);
-
乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
int cal(int n) { int ret = 0; int i = 1; for (; i < n; ++i) { //下面这段代码调用了f函数 ret = ret + f(i); // n } } int f(int n) { // n*n int sum = 0; int i = 1; for (; i < n; ++i) { sum = sum + i; } return sum; }
我们可以分析一下
第一段for循环 时间复杂度为O(n);
第二段fn函数 时间复杂度为O(n);
因为在第一段for循环中调用了 fn函数
那么其时间复杂度就是 O(n*n)==>O(n^2)
常见的时间复杂度实例分析
多项式量级(从小到大) | 非多项式量级 |
---|---|
常量阶O(1) | 指数阶O(2^n) |
对数阶O(logn) | 阶乘阶O(n!) |
线性阶O(n) | |
线性对数阶O(nlogn) | |
平方阶(n^x) |
接下来我们主要分析多项式时间复杂度,因为非多项式时间复杂度,随着数据规模n越来越大的时候,他的执行时间会急剧增加,是非常低效的算法
1.O(1)
就是没有循环,普通执行一行代码的复杂度
这个O(1)是一种方法,即使执行几十行代码,时间复杂度也是O(1)
2. O(logn),O(nlogn)
我们通过例子来分析
i=1;
while (i <= n) {
i = i * 2;
}
我们每执行一次循环,i=i*2
就会乘一次2,
进行一个运算可以得到
(1) 2^1
(2) 2^2
(3) ....
(n)2^x=n
转换成对数 即log2n
所以时间复杂度为O(logn)
循环执行N遍 就是O(nlogn);
3.O(m+n),O(m*n)
int cal(int m, int n) {
int sum_1 = 0;
int i = 1;
for (; i < m; ++i) {
sum_1 = sum_1 + i; // m
}
int sum_2 = 0;
int j = 1;
for (; j < n; ++j) {
sum_2 = sum_2 + j; // n
}
return sum_1 + sum_2;
}
看上面的代码,这段代码中有两个量级 m和n
因为无法比较两个谁大
所以时间复杂度是O(m+n)
如果是两个循环嵌套的话,那么复杂度就是O(m*n)
空间复杂度分析
空间复杂度表示方法类似于时间复杂度,但是会简单很多
同样都是使用 O进行表示
S(n)=O(f(n)
- S(n)表示存储空间总和
- f(n)表示代码所开辟空间
- O()表示代码开辟的空间与存储空间成正比
void print(int n) {
int i = 0;
int[] a = new int[n];
for (i; i <n; ++i) {
a[i] = i * i;
}
for (i = n-1; i >= 0; --i) {
print out a[i]
}
}
- int i=0 开辟了一块空间
- int[] a = new int[n]; 申请了一块n大小的数组存储空间
- 其余代码就没有执行开辟空间的操作了
- 所以空间复杂度就是O(n)
对比于时间复杂度,空间复杂度真的简单很多,只需观察开辟的空间
如果能用空间换时间,很多人估计都会选择空间换时间
常见的空间复杂度就是 O(1)、O(n)、O(n2 )
本文来自博客园,作者:CodeSpirit,转载请注明原文链接:https://www.cnblogs.com/codespirit-zx/p/15292622.html