數據結構與算法的誕生是讓計算機「執行的更快」、「更省空間」的。前端
從「執行時間」和「佔用空間」兩個方面來評判數據結構與算法的好壞。web
用「時間複雜度」和「空間複雜度」來描述性能問題,二者統稱爲複雜度。算法
複雜度描述的是算法執行時間(或佔用空間)與數據規模的增加關係。編程
輔助度分析有不依賴執行環境、成本低、效率高、易操做、指導性強的特色。數組
複雜度描述的是算法執行時間(或佔用空間)與數據規模的增加關係。bash
方法:「大 O 表示法」數據結構
算法的「執行時間」與每行代碼的「執行次數」成正比【T(n) = O(f(n)) 】=》其中T(n)表示算法執行總時間,f(n)表示每行代碼執行總次數,而n每每表示數據的規模。性能
因爲時間複雜度描述的是算法執行時間與數據規模的增加變化趨勢,常量階、低階以及係數實際上對這種增加趨勢不產決定性影響,因此在作時間複雜度分析時忽略這些項。ui
[單段代碼看頻率]:看代碼片斷中「循環代碼」的時間複雜度。spa
[多段代碼看最大]:若是多個 for 循環,看「嵌套循環最多」的那段代碼的時間複雜度。
[嵌套代碼求乘積]:循環、遞歸代碼,將內外嵌套代碼求乘積去時間複雜度。
[多個規模求加法]: 法有兩個參數控制兩個循環的次數,那麼這時就取兩者複雜度相加。
全部代碼的「執行時間 T(n)」 與每行代碼的「執行次數n」 成正比【T(n) = O(f(n)) 】。
#####二、分析的三個方法 ■ 最多法則
忽略掉公式中的常量、低階、係數,取最大循環次數就能夠了,也就是循環次數最多的那行代碼。
▍Example
1 // 求n個數字之和
2 int xiaolu(int n) {
3 int sum = 0;
4 for (int i = 1; i <= n; ++i) {
5 sum = sum + i;
6 }
7 return sum;
8 }
複製代碼
▍分析 第二行是一行代碼,也就是常量級別,與 n 沒有關係,能夠忽略,4、五行代碼是咱們重點分析對象,與 n 有關,時間複雜度就是反映執行時間和 n 數據規模的關係。求 n 個數據之和須要執行 n 次。因此時間複雜度爲 O(n)。
■ 加法法則
總複雜度等於循環次數最多的那段複雜度。
▍Example
1 int xiaolu(int n) {
2 int sum = 0;
3 //循環一
4 for (int i = 1; i <= 100; j++) {
5 sum = sum + i;
6 }
7 //循環二
8 for (int j = 1; j <= n; j++) {
9 sum = sum + i;
10 }
11 }
複製代碼
▍分析 上邊有兩個循環,一個循環 100 次,另外一個循環 n 次,咱們選擇循環次數最多的那一個且和「數據規模 n 」相關的循環。由上可知,咱們很容易選出循環二,即和數據規模 n 有關,循環次數最多,循環次數最多的那段代碼時間複雜度就表明整體的時間複雜度,爲 O(n) ;
■ 乘法法則
當咱們遇到嵌套的 for 循環的時候,怎麼計算時間複雜度呢?那就是內外循環的乘積。
▍Example
1 for (int j = 1; j <= n; j++) {
2 for(int i = 1; i <= n; i++)
3 sum = sum + i;
4 }
複製代碼
▍分析 外循環一次,內就循環 n 次,那麼外循環 n 次,內就循環 n*n 次。因此時間複雜爲 O(n²)。
表示算法的「存儲空間」與「數據規模」之間的增加關
▍Example
int i = 0;
int[] a = new int[n];
for (i; i <n; ++i) {
a[i] = i * i;
}
複製代碼
▍分析 在全部代碼中,咱們很容易尋找到存儲空間相關的代碼,就是第二行,申請了一個 n 大小的存儲空間,因此空間複雜度爲 O(n)。
O(1)、O(n)、O(n²)。
■ O(1)
常量級的時間複雜度表示方法,不管是一行代碼,仍是多行,只要是常量級的就用 O(1) 表示。
▍Example
1 int i = 1;
2 int j = 2;
3 int sum = i + j;
複製代碼
▍分析 由於這三行代碼,也就是常量級別的代碼不隨 n 數據規模的改變而改變。(循環、遞歸除外)
■ O(logn) | O(nlogn)
「對數階時間複雜度」,最難分析的一種時間複雜度。
▍Example
1 i=1;
2 while (i <= n) {
3 i = i * 3;
4 }
複製代碼
▍分析 要求這段代碼的時間複雜度就求這段代碼執行了多少次,看下圖具體分析。
▍補充 不論是以 2 爲底、以 3 爲底,仍是以 10 爲底,能夠把全部對數階的時間複雜度都記爲 O(logn),由於對數之間能夠轉換的,參照高中課本。
■ O(m+n) | O(m*n)
參照上邊講到的加法和乘法法則。
所謂的最好、最壞時間複雜度分別對應代碼最好的狀況和最壞的狀況下的執行。
▍Example
1 //在一個 array 數組中查找一個數據 a 是否存在
2for (int i = 1; i < n; i++) {
3 if (array[i] == a) {
4 return i;
5 }
6 }
複製代碼
▍分析 ① 最好狀況就是數組的第一個就是咱們要查找的數據,上邊代碼之執行一遍就能夠,這種狀況下的時間複雜度爲最好時間複雜度,爲 O(1)。
② 最壞的狀況就是數組的最後一個纔是咱們要查找的數據,須要循環遍歷 n 遍數組,也就對應最壞的時間複雜度爲 O(n)
平均時間複雜度須要藉助機率論的知識去分析,也就是咱們機率論中所說的加權平均值,也叫作指望值。
▍分析 好比上方的例子,假設咱們查找的數據在數組中的機率爲 1/2;出如今數組中的機率爲 n/1,根據下邊的公式就能夠算出出現的機率爲 1/2n
而後咱們再把每種狀況考慮進去,就能夠計算出平均時間複雜度。■ 幾種複雜度性能對比
記錄了三本學渣從 0 到 1 的編程故事,是一個致力於原創「數據結構與算法」之美的「web 前端」 技術號。
公衆號回覆 「葵花寶典」 便可領取小鹿收藏的自學資料。