【数据结构入门】更全面的实例让你快速理解时间复杂度&空间复杂度
刚开始学算法开篇就是复杂度计算,刚开始学习的时候以为并不是很重要,后面 才意识到时间复杂度可以让你更好的掌握算法效率,虽然不是非他不可,但可以锦上添花~
一、算法的时间复杂度
1、概念:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。
记作:T(n) = O(f(n));
表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率是形同的。
** 自己的理解:**
也就是说f(n)的增长率可以表示执行时间的增长率,从而反映该算法的时间复杂度。而f(n)表示的是该算法总共执行的次数。所以,可以通过计算代码中函数执行的次数来表示时间复杂度。
常用大写O()来体现时间复杂度,即大O记法。
常见的有0(1),O(n),O(n2)…
2.推导大O阶的方法
1)去掉运行时间中的所有加法常数,如果时间复杂度已经是常量,用常量1取代其他所有常量。(例如 n2+n+2,直接变为 n{{2}}+n)
2)只保留最高项。(n2+n 变成 n2)
3)如果最高项存在但是系数不是 1,去掉系数。(2n2直接变为n2)
举个例子大家就明白啦~
3.几种基础结构的时间复杂度
1)顺序结构
较为简单,对于分支结构,如:
int sum = 0,n = 100;
sum = n*(n+1)/2;
sum = n*(n+1)/2;
sum = n*(n+1)/2;
无论执行多少次,根据O阶推导方法第一条,时间复杂度都为O(1);
2)循环结构
int count = 1;
while(count < n){
count = count *2;
}
循环结构一般难点就在于判断循环的次数。
该循环在cout > n 的情况下退出,那么也就是要知道什么情况下cout >n;
也就是有多少个2相乘以后大于n,即2x = n ,x = log2n。
3)循环嵌套
int i,j;
for(i = 0;i < n;i++){
for(j = i;j <n;j++){ //注意j = i!!!!!
int sum = 0;
}
当i=0时,内循环执行n次,i=1时,内循环执行n-1次,以此类推,i=n-1时,执行1次;
由此可得执行总数为:
n+(n-1)+…+1=n(n+1)/2=n2/2+n/2
根据大O阶原则,保留最高项并删去系数, 最终时间复杂度为O(n2)
4)方法调用
方法调用相对比较复杂~
void function (int count){
for(i = 0; i < n i++){
count = 0;
}
}
//主函数
n++; //执行次数 1次
function(n); //执行次数 n 次
for(i = 0; i < n ; i ++){ // 执行次数 n^2^次
function(i);
}
for(i = 0;i < n; i++){ //执行次数 n(n-1)/2 次
for( j = i; j < n ; j ++){
count = 0;
}
}
所以总执行次数为f (n)=1+n+n2+n(n-1)/2
根据大O接方法,最终时间复杂度为O(n2)。
4.常用的时间复杂度的排序
列举了几种常见的算法时间复杂度的比较(又小到大):
O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(n2)平方阶 < O(n3)(立方阶) < O(2n) (指数阶)
二、算法的空间复杂度
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。
空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。
举个例子叭~
// 计算Fibonacci的空间复杂度?
long[] Fibonacci(int n)
{
long[] fibArray = new long[n + 1];
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n ; i++) {
fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
}
return fibArray;
}
动态开辟了N个空间,空间复杂度为 O(N)