複雜度也叫漸進複雜度,包括時間複雜度和空間複雜度,用來分析算法執行效率與數據規模之間的增加關係。c++
複雜度分析能夠在初期幫助程序員預估該程序的性能耗費。程序員
時間複雜度用於表示算法的時間耗費與數據規模增加之間的關係算法
空間複雜度用於表示算法的存儲空間與數據規模增加之間的關係數組
總複雜度等於量級最大的那段代碼的複雜度,好比說一個程序中存在兩段不一樣時間複雜度的代碼塊:bash
int f(int n) {
int sum = 0;
for (int i = 0; i < n; ++i) {
sum ++;
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
sum ++;
}
}
return sum;
}
複製代碼
第一個for循環的時間複雜度T1,和第二個嵌套for循環的時間複雜度T2分別爲:函數
那麼整個程序的時間複雜度爲:性能
若是量級大的代碼塊有多個,而咱們沒法事先評估誰的量級大,就不能簡單地省略其中一個,例如:ui
int f(int n, int m) {
int sum = 0;
for (int i = 0; i < n; ++i) {
sum ++;
}
for (int i = 0; i < m; ++i) {
sum ++;
}
return sum;
}
複製代碼
該函數的時間複雜度爲:spa
乘法法則: 嵌套代碼的複雜度等於嵌套內外代碼複雜度的乘積,例如:code
int f(int n, int m) {
int sum = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
sum += j;
}
}
return sum;
}
複製代碼
該函數的時間複雜度爲:
對於常量複雜度而言,執行時間不隨 n 的增大而增加的代碼,咱們都記做 O(1) 。 通常狀況下,只要算法中不存在循環語句、遞歸語句,即便有成千上萬行的代碼,其時間複雜度也是Ο(1)
對於對數階複雜度而言, 無論是以 2 爲底、以 3 爲底,仍是以 10 爲底,咱們能夠把全部對數階的時間複雜度都記爲O(logn)
對於指數階、階乘階複雜度而言, 當數據規模 n 增大,算法的執行時間會急劇增長 ,所以這兩類時間複雜度的算法是很是低效的算法不推薦使用
上述狀況是程序必須執行完全部代碼得出的時間複雜度。而在不少狀況下,咱們不須要進行完整的遍歷或遞歸,例如查找一個數組中是否存在5:
int val[n];
bool find() {
for (int i = 0; i < n; i++) {
if (val[i] == 5) {
return true;
}
}
return false;
}
複製代碼
最好狀況時間複雜度是最理想狀況下執行這段代碼的時間複雜度,體如今上述代碼中,就是數組第一個元素是5,所以最好狀況時間複雜度爲O(1)
最壞狀況時間複雜度是最糟糕狀況下執行這段代碼的時間複雜度 ,體如今上述代碼中,就是數組中不存在元素5,所以最壞狀況時間複雜度爲O(n)
平均狀況時間複雜度是考慮全部可能發生的狀況、機率、以及對應耗費的時間,而後取平均值,體如今上述代碼中,就是考慮n+1種狀況(5出如今0~n-1位置 和 5沒有出現)及其機率、對應耗費的時間,獲得:
因爲時間複雜度能夠省略掉係數、低階、常量,把這個公式簡化以後獲得的平均時間複雜度就是 O(n)
規則與時間複雜度的三點相似,再也不贅述
咱們能夠經過空間複雜度,來預估程序所耗費的內存。好比:
const int N = 1000000;
int[] val = new int[N];
複製代碼
int型佔四字節,對於O(n)空間複雜度的程序來講,當n爲1e6時,耗費的內存爲:
比較常見的空間複雜度有:
相比時間複雜度, O(logn)、O(nlogn)
等對數階複雜度平時幾乎用不到~