时间复杂度与空间复杂度
一个程序的优劣主要从时间和空间两个维度去考量
一、时间复杂度
时间复杂度是根据算法写成的程序在执行的过程中耗费时间的长度,时间复杂度过高的低效算法可能这辈子都等不到运行结果
比较常见的时间复杂度量级有 O(1),O(n),O(n²),O(logN),O(nlogN),O(2^n)
1.O(1)
无论代码执行了多少行,只要没有循环的结构,那么代码时间复杂度就是O(1)
int i = 5:
++i;
2.O(n)
只有一个循环,函数中的语句会执行n次,所以时间复杂度是O(n)
for(int i = 0;i<n;++i){
j = i;
}
3.O(n²)
嵌套了两层循环,函数中的语句会执行n*n次,所以时间复杂度是O(n²)
for(int i = 0,i<n;++i){
for(int j = 0;j<n;++j){
j = i;
}
}
这里要注意嵌套的关系,如果程序如下所示的话,并非嵌套结构的话。第一个for循环时间复杂度是O(n),第二个for循环时间复杂度也是O(n),它们两者是相加的关系所以时间复杂度并不是O(n²)而是O(n)
for(int i = 0;i<n;++i){
j = i;
}
for(int j = 0;j<n;++j){
i = j;
}
同理嵌套k层循环的时候时间复杂度就是O(n^k)
4.O(logN)
for(int i = 1;i<n:i *= 2){
j = i;
}
在for循环里每次执行完j=i的语句操作,i都会*2,当执行x次以后i>=n了就会退出循环,所以x = log2^n;所以这个循环的时间复杂度是O(logN),在二分查找中时间复杂度就是O(logN)
5.O(nlogN)
同上,执行n次时间复杂度为logN的程序,他的时间复杂度就是nlogN
for(int m = 0;m<n;++m){
for(int i = 1;i<n:i *= 2){
j = i;
}
}
6.O(2^n)
在使用递归求斐波那契数列问题的时候代码如下:
int fibonacci(int i) {
if(i <= 0) return 0;
if(i == 1) return 1;
return fibonacci(i-1) + fibonacci(i-2);
}
递归算法的时间复杂度 = 递归的次数 * 每次递归的时间复杂度
由于计算fibonacci(5)的时候要计算fibonacci(4),fibonacci(3),计算fibonacci(4)fibonacci(3)的时候又要计算fibonacci(3),fibonacci(2),fibonacci(2),fibonacci(1),递归的次数 = 1+2+4+…所以改递归算法的时间复杂度是O(2^n)
二、空间复杂度
空间复杂度是根据算法写成的程序在执行时占用存储单元的长度,空间复杂度过高的算法可能导致使用的内存超限,造成程序的非正常中断
常见的空间复杂度量级有O(1),O(n),O(logN)
1.O(1)
如果算法在执行的过程中所开辟的空间并不会随着n的变化而变化,那么算法的空间复杂度就是O(1)
for (int i = 0; i < n; i++) {
++j;
}
2.O(n)
在函数执行过程中vector数组大小随着i的增加成线性增长,所以空间复杂度是O(n)
vector<int> res;
for (int i = 0; i < n; i++) {
res.push_back(i);
}
当使用递归算法的时候,递归算法的空间复杂度 = 每次递归的空间复杂度 * 递归深度(递归调用次数)
递归每次所需的空间都要调用栈,递归深度 = 栈的长度
int fibonacci(int i) {
if(i <= 0) return 0;
if(i == 1) return 1;
return fibonacci(i-1) + fibonacci(i-2);
}
在斐波那契数列中,该算法的每次递归的空间复杂度是常数,递归次数是n,所以该算法的空间复杂度是O(n)
3.O(logN)
在使用递归法二分查找的过程中,每次递归的空间复杂度是常数,递归的次数是logN,所以该算法的 空间复杂度是O(logN)
int BinarySearchRecursive(int *array, int low, int high, int target) {
if ( low > high )
return -1;
int mid = ( low + high )/2;
if (array[mid] == target )
return mid;
else if ( array[mid] < target )
return BinarySearchRecursive(array, mid+1, high, target);
else
return BinarySearchRecursive(array, low, mid-1, target);
}