時間複雜度 時間複雜度實際是一個函數,該函數計算的是執行基本操作的次數
時間複雜度計算方法
(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)