衡量演算法好壞的標準就是其複雜度,複雜度又分為:時間複雜度(time complexity)空間複雜度(space complexity)兩種。
提高**的效率,本質上就是降低**的複雜度,時間寶貴,而空間相對廉價,時間是不可逆的,空間可以在開闢,所以當二者相碰撞時,我們選擇用空間換取時間,首先降低時間複雜度。
一、時間複雜度
時間複雜度分析
我們知道常數項對函式的增長速度影響並不大,所以當 t(n) = c,c 為乙個常數的時候,我們說這個演算法的時間複雜度為 o(1);如果 t(n) 不等於乙個常數項時,直接將常數項省略。
比如
printf
("hello,world\n");
printf
("hello,world\n");
t(n)
=2,所以我們說這個函式(演算法)的時間複雜度為 o(1
)。t(n)= n +
29,此時時間複雜度為 o
(n)。
我們知道高次項對於函式的增長速度的影響是最大的。n^3 的增長速度是遠超 n^2 的,同時 n^2 的增長速度是遠超 n 的。 同時因為要求的精度不高,所以我們直接忽略低項。
比如
t
(n)= n^
3+ n^
2+ n +
29,此時時間複雜度為 o
(n^3
)。
因為函式的階數對函式的增長速度的影響是最顯著的,所以我們忽略與最高端相乘的常數。
比如
t
(n)=
3n^3,此時時間複雜度為 o
(n^3
)。
綜合起來:如果乙個演算法的執行次數是 t(n),那麼只保留最高次項,同時忽略最高項的係數後得到函式 f(n),此時演算法的時間複雜度就是 o(f(n))。
如何分析一段**的時間複雜度?三個比較實用的方法
1、只關注迴圈執行次數最多的的一段**
大 o 這種複雜度表示方法只是表示一種變化趨勢。我們通常會忽略掉公式中的常量、低階、係數,只需要記錄乙個最大階的量級就可以了。所以,我們在分析乙個演算法、一段**的時間複雜度的時候,也只關注迴圈執行次數最多的那一段**就可以了。這段核心**執行次數的 n 的量級,就是整段要分析**的時間複雜度。
return sum;
}
2、**都是常量級別的執行時間,與n的大小無關,所以對於複雜度並沒有影響。迴圈執行次數最多的是4、5行**,所以這塊**要重點分析。那兩行**執行了n次,所以總的時間複雜度就是o(n)
加法法則:總複雜度等於量級最大的那段**的複雜度
如果一整段**由三小段**構成,且三小段**的時間複雜度(分別是o(1), o(n), o(n2)),我們取其中最大的量級。所以,整段**的時間複雜度就為 o(n2)。也就是說:總的時間複雜度就等於量級最大的那段**的時間複雜度。那我們將這個規律抽象成公式就是:
如果 t1(n)=o(f(n)),t2(n)=o(g(n));那麼 t(n)=t1(n)+t2(n)=max(o(f(n)), o(g(n))) =o(max(f(n), g(n))).
乘法法則:巢狀**的複雜度等於巢狀內外**複雜度的乘積
類似巢狀迴圈的,都是用乘法來處理
時間複雜度的計算:(就找執行次數最多的地方)
如果經歷過以下**片段,那麼它的時間複雜度是多少呢?讓我們依次分析
printf
("a\n");
printf
("a\n");
printf
("a\n"
);
很顯然,時間複雜度為o(1);
for
(i=1
;i<=n;i++
)
最後時間複雜度為o(n);
for
(i=1
;i<=n;i++
)}
最後o(nx(n+1)/2),時間複雜度為o(n^2);
for
(i=1
;i<=n;i++
)}
時間複雜度為o(nlog2n);
for
(i=1
;i<=n;i++)}
}
其實這段**看起來迴圈比較多,但是我們要透過現象看本質,這三層迴圈巢狀最終都作用在了輸出語句上,當i=1時,輸出了一次,i=2時,輸出了1+2次,i=3時,輸出了1+2+3次,i=4時,輸出了1+2+3+4次… …,每一次的輸出次數都是一次等差數列的和,則總次數為:
(媽媽!字怎麼可以這麼難看!)
二、空間複雜度
既然時間複雜度不是用來計算程式具體耗時的,那麼我也應該明白,空間複雜度也不是用來計算程式實際占用的空間的。
空間複雜度是對乙個演算法在執行過程中臨時占用儲存空間大小的乙個量度,同樣反映的是乙個趨勢,我們用 s(n) 來定義。
空間複雜度比較常用的有:o(1)、o(n)、o(n²),我們下面來看看:
空間複雜度 o(1)
如果演算法執行所需要的臨時空間不隨著某個變數n的大小而變化,即此演算法空間複雜度為乙個常量,可表示為 o(1)
舉例:
int i =1;
int j =2;
++i;
j++;
int k = i + j;
**中的 i、j、k所分配的空間都不隨著處理資料量變化,因此它的空間複雜度 s(n) = o(1)
空間複雜度 o(n)
我們先看乙個**:
int
m =newint
[n]for
(i=1
; i<=n;
++i)
這段**中,第一行new了乙個陣列出來,這個資料占用的大小為n,這段**的2-6行,雖然有迴圈,但沒有再分配新的空間,因此,這段**的空間複雜度主要看第一行即可,即 s(n) = o(n)
常見演算法的複雜度及其穩定性
時間複雜度與空間複雜度
空間複雜度 space complexity 是對乙個演算法在執行過程中臨時占用儲存空間大小的量度,記做s n o f n 比如直接 插入排序 的時間複雜度 是o n 2 空間複雜度是o 1 而一般的 遞迴演算法就要有o n 的空間複雜度了,因為每次遞迴都要儲存返回資訊。乙個演算法的優劣主要從演算法...
時間複雜度與空間複雜度
本文是對時間複雜度以及空間複雜度的乙個理解 時間複雜度 由於環境的不同,同樣的 執行所需要的時間是不同的,所以是不能拿來比較的 而函式中執行的次數確實一樣的 所以時間複雜度就是 程式每個迴圈中的語句總共會執行的次數 時間複雜度的表示方法 大o漸進表示法 o f n 這裡的f n 是什麼呢?void ...
時間複雜度與空間複雜度
本文部分取自搜狗百科 在求演算法效率時,通常有事前分析和事後分析兩種方法,事後分析因為必須實際檢驗過後才能得出答案,且可能由於硬體方面等外部原因影響結果而不被推廣,事前分析的主要就是在考量乙個演算法的基本執行次數,這就是時間複雜度。時間複雜度 一般情況下,演算法中基本操作重複執行的次數是問題規模n的...