时间复杂度 时间复杂度实际是一个函数,该函数计算的是执行基本操作的次数
时间复杂度计算方法
(1)数次数
(2)O()
1. 用常数1取代运行时间中的所有加法常数
2. 只保留最高项
3. 最高项系数不为1的改为1
注意:选取最坏时间复杂度即选取增长最快的项
递归的时间复杂度=递归总次数*每次递归中基本操作所执行是次数
空间复杂度 函数中创建对象的个数关于问题规模表达式
不是计算实际占用的空间,而是计算整个算法的辅助空间单元的个数,与问题规模没有关系(简单理解就是算法执行时创建的变量个数(包括临时变量)
空间可以重用,算递归最坏(最深)的一种情况
常用的时间复杂度所耗费的时间从小到大依次是:
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)
曲线越陡,时间复杂度越大,越不好
分析二分查找、递归实现的斐波那契数列的时间/空间复杂度
二分查找
while(left <= right)
{
int mid=left+(right-left)/2;
if(arr[mid] == n)
{
printf("找到了%d: ", mid);
break;
}
else if(arr[mid] < n)
{
left = mid+1;
}
else
{
right = mid-1;
}
}
因为二分查找每次排除掉一半的不适合值,所以对于n个元素的情况:
一次二分剩下:n/2
两次二分剩下:n/2/2 = n/4
。。。
m次二分剩下:n/(2^m)
在最坏情况下是在排除到只剩下最后一个值之后得到结果,所以为
n/(2^m)=1;
2^m=n;
所以时间复杂度为:log2(n)
辅助空间单元数是常数。所以空间复杂度是0(1)
递归实现的斐波那契数列
int fib_recursion(int n)
{
if (n <= 2)
return 1;
else
{
return fib(n - 1) + fib(n - 2);
}
}
每一步计算都被分成计算前两个斐波那契数,以此类推。那么这就形成了一颗二叉树,虽然不是满二叉树,但是我们分析的是最坏时间复杂度,而且只要估算出来递归次数随N增长的趋势即可,故可以近似将它看成满二叉树,其中的节点数就是计算的次数,也就是复杂度,由公式:节点数=2^h-1(h为树的高度)可得O(2^n)。
递归的时间复杂度是: 递归次数*每次递归中执行基本操作的次数,所以时间复杂度是: O(2^N)
递归最深的那一次所耗费的空间足以容纳它所有递归过程。递归产生的栈侦是要销毁的,所以空间也就释放了,要返回上一层栈侦继续计算+号后面的数,所以它所需要的空间不是一直累加起来的,之后产生的栈侦空间都小于递归最深的那一次所耗费的空间。
递归的深度*每次递归所需的辅助空间的个数 ,所以空间复杂度是:O(N)