如何衡量一个算法的好坏
1.时间复杂度
一个算法所花费的时间与其中
语句的执行次数成正比例
,算法中基本操作的执行次数
,为算法的时间复杂度。
1.1 大O的渐进表示法
- 用常数1取代运行时间中的所有加法常数。
- 在修改后的运行次数函数中,只保留最高阶项。
- 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
1.2 有关时间复杂度的练习
例1:计算func1的时间复杂度?
如上图 F(N)=N^2+2*N+10
使用大O的渐进表示法以后,Func1的时间复杂度为:O(N^2)
例2:计算func2的时间复杂度?
如上图 F(N)=2*N+10
在修改后的运行次数函数中,只保留最高阶项。如果最高阶项存在且不是1,则去除与这个项目相乘的常数。
使用大O的渐进表示法以后,Func2的时间复杂度为:O(N)
例3:计算func3的时间复杂度?
如上图
F(N)=M+N
使用大O的渐进表示法以后,Func3的时间复杂度为:O(M+N)
例4:计算func4的时间复杂度?
如上图
F(N)=100
常数次,Func4的时间复杂度为:O(1)
例4:计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n){
assert(a);
for(size_t end = n; end > 0; --end){
int exchange = 0;
for(size_t i = 1; i < end; ++i){
if(a[i-1] > a[i]){
Swap(&a[i-1], &a[i]);
exchange = 1;
}
}
if(exchange == 0)
break;
}
}
此算法是一个
冒泡排序
,交换的次数可以看作是一个等差数列
,所以准确的次数为等差数列前N项和(N+1)*N/2
,即冒泡排序的时间复杂度为:O(N^2)
例5:计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x){
assert(a);
int begin = 0;
int end = n;
while(begin < end){
int mid = begin+((end - begin) >> 1);
if (a[mid] < x)
begin = mid + 1;
else if (a[mid] > x)
end = mid;
else
return mid;
}
return -1;
}
此算法是一个
二分查找(折半查找)
,即时间复杂度为:O(logN)
例6:计算Factorial的时间复杂度?
long long Factorial(size_t N){
return N < 2 ? N : Factorial(N-1) * N;
}
时间复杂度为:
O(N)
例7:计算斐波那契递归fibonacci的时间复杂度?
int fibonacci(int N){
return N < 2 ? N : fibonacci(N-1) + fibonacci(N-2);
}
时间复杂度为:
O(2^N)
递归的时间复杂度 = 递归的次数 * 每次递归执行的次数
常见的时间复杂度 O(1) < O(logN) < O(N) < O(N*logN) < O(N^2) < O(2^N)
2.空间复杂度
空间复杂度是对一个算法在运行过程中
临时占用存储空间大小的度量
。计算的是变量个数
,空间复杂度不是程序占用了多少bytes的空间,因为这个没太大意义,所以空间复杂度算的是变量的个数。
2.1 有关时间复杂度的练习
例1: 计算Bubblesort的空间复杂度
循环走了n 次,利用的是一个空间,所以空间复杂度是O(1)
例2:计算Factorial的空间复杂度
递归调用了N层,每次调用建立一个栈帧,每个栈帧使用了常数个空间O(1),合起来就是O(N),调用时,建立栈帧;返回时,销毁。即空间复杂度为:
O(N)
.