时间复杂度和空间复杂度
提示:以下是本篇文章正文内容,下面案例可供参考
一、算法效率?
算法复杂度由时间复杂度和空间复杂度组成,时间和空间复杂度也是衡量一个算法好坏的标准。
二、时间复杂度
1.概念
时间复杂度:一个算法运行完成后所需要的时间,从理论上来说只有在机器上运行完成后才能知道。如果所有的算法都在机器上运行一遍,那就太麻烦了,所以我们通常根据算法的执行次数来判断【一个算法所花费的时间与其中语句的执行次数成正比例,算法中执行次数越多,花费时间就越长】,这就是算法的时间复杂度。
2.大O的渐进表示法
推导大O阶:
1、用常数1取代运行时间中的所有加法常数;(计算机的运行速度是非常快的,一次和几百次对计算机来说区别并不大,即算法空间复杂度为一个常量,可表示为 O(1))
2、在修改后的运行次数函数中,只保留最高阶项;(在函数中对表达式的结果影响最大的一项就是最高阶项)
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶;
1. 大O阶(常数阶):
void Func1() {
int a = 1;
int b = 2;
int c = 3;
}
上面的方法中的时间复杂度为O(1)
; 这是怎么得来的呢?
根据【推导大O阶】指导思想:
- 根据【推导大O阶第一条】:我们可以确定方法执行三次(只要明确知道次数),则用常数1取代运行时间中的所有加法常数;
2. 大O阶(对数阶):
void Func2 (int n){
int i=1;
while(i<=n){
i = i * 2;
}
}
上面的方法中的时间复杂度为O(log n)
; 这是怎么得来的呢?
- 根据【推导大O阶第二条】:假设N的值越来越大,对【i * 2^n】表达式结果影响最大的只有 2 ^n,所以保留
O(log n)
;
3. 大O阶(线性阶):
void Func3(int N, int M) {
int count = 0;
for (int k = 0; k < M; ++k) {
++count;
}
for (int k = 0; k < N; ++k) {
++count;
}
printf("%d\n", count);
}
上面的方法中 【 ++count】操作进行了【N+M】次计算,通常我们称该方法的时间复杂度为O(N+M)
; 这是怎么得来的呢?
根据【推导大O阶】指导思想:
- 根据【推导大O阶第二条】:无法判断,因为N或M都可能会对表达式结果造成最大的影响;
- 根据【推导大O阶第三条】:无法确定最高阶,则无法去除与这个项目相乘的常数;
- 综合上面得出时间复杂度为
O(N+M)
4. 大O阶(线性对数阶):
void Func4(int n){
int i=0;
for(;i<=n;i++){
Func4_1(n);
}
}
void Func4_1(int n){
int i=1;
while(i<=n){
i = i * 2;
}
}
上面的方法中的时间复杂度为O(n * log n)
; 这是怎么得来的呢?
- 根据【推导大O阶第二条】:假设N的值越来越大,对【n* i* 2 ^n】表达式结果影响最大的只有n*2 ^n,
所以保留O(n * log n)`;
5. 大O阶(平方阶):
void Func5(int N) {
int count = 0;
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
++count;
}
}
for (int k = 0; k < 2 * N; ++k) {
++count;
}
int M = 10;
while (M--) {
++count;
}
printf("%d\n", count);
}
上面的方法中 【 ++count】操作进行了N²+2N+10次计算,通常我们称该方法的时间复杂度为O(N²)
; 这是怎么得来的呢?
根据【推导大O阶】指导思想:
- 根据【推导大O阶第二条】:假设N的值越来越大,对【N²+2N+10】表达式结果影响最大的只有N²,所以保留N²;
- 根据【推导大O阶第三条】:最高阶项存在且不是1,则去除与这个项目相乘的常数;
- 综合上面得出时间复杂度为
O(N²)
3. 常见时间复杂度
- 常数阶O(1)
- 对数阶O(logN)
- 线性阶O(n)
- 线性对数阶O(nlogN)
- 平方阶O(n²)
- 立方阶O(n³)
- K次方阶O(n^k)
- 指数阶(2^n)
三、空间复杂度
空间复杂度:主要判断一个算法执行中临时所需要的额外空间,空间复杂度基本上就 O(1)和 O(N)两种情况。
判断规则
- 明确知道所需临时空间的,可表示为 O(1);
- 所需要的临时空间随着某个变量的大小而变化,可表示为 O(N);
该表来源于网络,侵权请联系删除