⑴ 找出算法中的基本語句;
算法中執行次數最多的那條語句就是基本語句,通常是最內層循環的循環體。
⑵ 計算基本語句的執行次數的數量級;
只需保留f(n)中的最高次冪正確即可,可以忽略所有低次冪和最高次冪的系數。
⑶ 用大Ο記號表示算法的時間性能。
將基本語句執行次數的數量級放入大Ο記號中。
如果算法中包含嵌套的循環,則基本語句通常是最內層的循環體,如果算法中包含並列的循環,則將並列循環的時間復雜度相加。例如:
for (i=1; i<=n; i++)
x++;
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
x++;
第一個for循環的時間復雜度為Ο(n),第二個for循環的時間復雜度為Ο(n²),則整個算法的時間復雜度為Ο(n+n²)=Ο(n²)。
注、加法原則:T(n)=O(f(n))+O(g(n))=O(max(fn,gn))
常見的算法時間復雜度由小到大依次為:
Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n²)<Ο(n³)<…<Ο(2^n)<Ο(n!)<O(n^n)
Ο(1)表示基本語句的執行次數是一個常數,一般來說,只要算法中不存在循環語句,其時間復雜度就是Ο(1)。Ο(log2n)、Ο(n)、Ο(nlog2n)、Ο(n2)和Ο(n3)稱為多項式時間,而Ο(2n)和Ο(n!)稱為指數時間。計算機科學家普遍認為前者是有效算法,把這類問題稱為P類問題,而把后者稱為NP問題。
對於一個循環,假設循環體的時間復雜度為 O(n),循環次數為 m,則這個
循環的時間復雜度為 O(n×m)。
void aFunc(int n) { for(int i = 0; i < n; i++) { // 循環次數為 n
printf("Hello, World!\n"); // 循環體時間復雜度為 O(1)
} }
此時時間復雜度為 O(n × 1),即 O(n)。
對於多個循環,假設循環體的時間復雜度為 O(n),各個循環的循環次數分別是a, b, c...,則這個循環的時間復雜度為 O(n×a×b×c...)。分析的時候應該由里向外分析這些循環。
void aFunc(int n) { for(int i = 0; i < n; i++) { // 循環次數為 n for(int j = 0; j < n; j++) { // 循環次數為 n printf("Hello, World!\n"); // 循環體時間復雜度為 O(1) } } }
此時時間復雜度為 O(n × n × 1),即 O(n^2)。
對於順序執行的語句或者算法,總的時間復雜度等於其中最大的時間復雜度。
void aFunc(int n) { // 第一部分時間復雜度為 O(n^2)
for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { printf("Hello, World!\n"); } } // 第二部分時間復雜度為 O(n)
for(int j = 0; j < n; j++) { printf("Hello, World!\n"); } }
此時時間復雜度為 max(O(n^2), O(n)),即 O(n^2)。
對於條件判斷語句,總的時間復雜度等於其中 時間復雜度最大的路徑 的時間復雜度。
void aFunc(int n) { if (n >= 0) { // 第一條路徑時間復雜度為 O(n^2)
for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { printf("輸入數據大於等於零\n"); } } } else { // 第二條路徑時間復雜度為 O(n)
for(int j = 0; j < n; j++) { printf("輸入數據小於零\n"); } } }
此時時間復雜度為 max(O(n^2), O(n)),即 O(n^2)。
時間復雜度分析的基本策略是:從內向外分析,從最深層開始分析。如果遇到函數調用,要深入函數進行分析。