1、資料結構是用來幹嘛的?
資料結構與演算法的誕生是讓計算機「執行的更快」、「更省空間」的。
2、用什麼來評判資料結構與演算法的好壞?
從「執行時間」和「佔用空間」兩個方面來評判資料結構與演算法的好壞。
3、什麼是複雜度?
用「時間複雜度」和「空間複雜度」來描述效能問題,兩者統稱為複雜度。
4、複雜度描述了什麼?
複雜度描述的是演算法執行時間(或佔用空間)與資料規模的增長關係。
1、和效能分析相比有什麼優點?
輔助度分析有不依賴執行環境、成本低、效率高、易操作、指導性強的特點。
2、為什麼要複雜度分析?
複雜度描述的是演算法執行時間(或佔用空間)與資料規模的增長關係。
1、什麼方法可以進行復雜度分析?
方法:「大 O 表示法」
2、什麼是大 O 表示法?
演算法的「執行時間」與每行程式碼的「執行次數」成正比【T(n) = O(f(n)) 】=》其中T(n)表示演算法執行總時間,f(n)表示每行程式碼執行總次數,而n往往表示資料的規模。
3、大 O 表示法的特點?
由於時間複雜度描述的是演算法執行時間與資料規模的增長變化趨勢,常量階、低階以及係數實際上對這種增長趨勢不產決定性影響,所以在做時間複雜度分析時忽略這些項。
4、複雜度分析法則
-
[單段程式碼看頻率]:看程式碼片段中「迴圈程式碼」的時間複雜度。
-
[多段程式碼看最大]:如果多個 for 迴圈,看「巢狀迴圈最多」的那段程式碼的時間複雜度。
-
[巢狀程式碼求乘積]:迴圈、遞迴程式碼,將內外巢狀程式碼求乘積去時間複雜度。
-
[多個規模求加法]: 法有兩個引數控制兩個迴圈的次數,那麼這時就取二者複雜度相加。
時間複雜度
1、什麼是複雜度?
所有程式碼的「執行時間 T(n)」 與每行程式碼的「執行次數n」 成正比【T(n) = O(f(n)) 】。
#####2、分析的三個方法 ■ 最多法則
忽略掉公式中的常量、低階、係數,取最大迴圈次數就可以了,也就是迴圈次數最多的那行程式碼。
▍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 沒有關係,可以忽略,四、五行程式碼是我們重點分析物件,與 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²)。
空間複雜度
1、什麼是空間複雜度?
表示演算法的「儲存空間」與「資料規模」之間的增長關
▍Example
int i = 0;
int[] a = new int[n];
for (i; i <n; ++i) {
a[i] = i * i;
}
複製程式碼
▍分析 在所有程式碼中,我們很容易尋找到儲存空間相關的程式碼,就是第二行,申請了一個 n 大小的儲存空間,所以空間複雜度為 O(n)。
2、最常見的空間複雜度
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)
參照上邊講到的加法和乘法法則。
1、最好、最壞時間複雜度
所謂的最好、最壞時間複雜度分別對應程式碼最好的情況和最壞的情況下的執行。
▍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)
2、平均時間複雜度
平均時間複雜度需要藉助概率論的知識去分析,也就是我們概率論中所說的加權平均值,也叫做期望值。
▍分析 比如上方的例子,假設我們查詢的資料在陣列中的概率為 1/2;出現在陣列中的概率為 n/1,根據下邊的公式就可以算出出現的概率為 1/2n
然後我們再把每種情況考慮進去,就可以計算出平均時間複雜度。■ 幾種複雜度效能對比
公眾號:一個不甘平凡的碼農
記錄了三本學渣從 0 到 1 的程式設計故事,是一個致力於原創「資料結構與演算法」之美的「web 前端」 技術號。
公眾號回覆 “葵花寶典” 即可領取小鹿收藏的自學資料。