一,定義
時間複雜度:就是說執行算法需要消耗的時間長短,越快越好。在一個算法存在最好、平均、最壞三種情況,我們一般關注的是最壞情況,原因是最壞情況是任何輸入實例在運行時間的上界。
二,表示方法
一般用"大O符號表示法"來表示時間複雜度:T(n)=O(f(n)),n是影響複雜度變化的因子,f(n)是複雜度具體的算法。
三,如何推導出時間複雜度呢
1,如果運行時間是常數量級,用常數1表示;
2,只保留時間函數中的最高階項;
3,如果最高階項存在,則省去最高階項前面的係數
三,常見的時間複雜度量級
3.1,常數階O(1)
int a = 1;
int b = 2;
int c = 3;
我們假定每執行一行代碼所需要消耗的時間爲1個時間單位,那麼以上3行代碼就消耗了3個時間單位,那是不是這段代碼的時間複雜度爲O(n)呢 ?其實不是的,因爲大O符號表示法並不是用來表示算法的執行時間,它是用來表示代碼執行時間的增長變化趨勢。
3.2,線性階O(n)
for(i = 1; i <= n; i++) {
j = i;
j++;
}
第1行會執行1次,第2行和第3行會分別執行n次,總的執行時間也就是 2n + 1 次,那它的時間複雜度表示是 O(2n + 1) 嗎? No !
還是那句話:“大O符號表示法並不是用於來真實代表算法的執行時間的,它是用來表示代碼執行時間的增長變化趨勢的”。
所以它的時間複雜度其實是O(n);原則:只保留時間函數中的最高階項;如果最高階項存在,則省去最高階項前面的係數。
3.3,對數階O(logN)
int i = 1;
while(i < n) {
i = i * 2;
}
//或:
for(int i = 1; i < n; i = i*2){
printf("i = %d",i);
}
可以看到每次循環的時候 i 都會乘2,那麼總共循環的次數就是log2n,因此這個代碼的時間複雜度爲O(logn)。
這兒有個問題,爲什麼明明應該是O(log2n),卻要寫成O(logn)呢?
其實這裏的底數對於研究程序運行效率不重要,寫代碼時要考慮的是數據規模n對程序運行效率的影響,常數部分則忽略,同樣的,如果不同時間複雜度的倍數關係爲常數,那也可以近似認爲兩者爲同一量級的時間複雜度。
3.4,線性對數階O(nlogN)
for(m = 1; m < n; m++) {
i = 1;
while(i < n) {
i = i * 2;
}
}
線性對數階O(nlogN) 其實非常容易理解,將時間複雜度爲O(logn)的代碼循環N遍的話,那麼它的時間複雜度就是 n * O(logN),也就是了O(nlogN)。
3.5,平方階O(n²)
for(x = 1; i <= n; x++){
for(i = 1; i <= n; i++) {
j = i;
j++;
}
}
把 O(n) 的代碼再嵌套循環一遍,它的時間複雜度就是 O(n²) 了。
3.6,立方階O(n³),K次方階O(n^k)
參考上面的O(n²) 去理解就好了,O(n³)相當於三層n循環,其它的類似。
3.8,指數階(2^n)
四,常見算法對應時間複雜度
二分法查找,二叉樹遍歷,最優排序矩陣搜索,歸併排序
歡迎訂閱公衆號【從零開始學無線】,一起學習交流!