在進行演算法分析時,語句總的執行次數t(n)是關於問題規模n的函式,進而分析t(n)隨n的變化情況並確定t(n)的數量級。演算法的時間複雜度,
也就是演算法的時間量度,
記作t(n)=o(f(n))。它表示隨問題規模n的增大,演算法執行時間的增長率和f(n)的增長率相同,稱作演算法的漸進演算法時間複雜度,簡稱為時間複雜度。
其中f(n)是問題規模n的某個函式。
一般用大寫o()來表示演算法的時間複雜度寫法,通常叫做大o記法。
一般情況下,隨著n的增大,t(n)增長最慢的演算法為最優演算法。
o(1):常數階
o(n):線性階
o(n2):平方階
o(logn):對數階
用常數1取代執行時間中的所有加法常數
在修改後的執行函式中,只保留最高端項
如果最高端項存在且不是1,則去除與這個項相乘的常數
3.1常數階:
int sum = 0 ; n = 100; /*執行一次
*/sum = (1+n)*n/2; /*
執行一次
*/printf("%d
",sum); /*
執行一次
*/
這個演算法的執行次數f(n) = 3,根據推導大o階的方法,第一步是將3改為1,在保留最高端項是,它沒有最高端項,因此這個演算法的時間複雜度為o(1);
另外我們將sum = (1+n)*n/2;執行10次
int sum = 0 ; n = 100; /*執行一次
*/sum = (1+n)*n/2; /*
執行第1次
*/sum = (1+n)*n/2; /*
執行第2次
*/sum = (1+n)*n/2; /*
執行第3次
*/sum = (1+n)*n/2; /*
執行第4次
*/sum = (1+n)*n/2; /*
執行第5次
*/sum = (1+n)*n/2; /*
執行第6次
*/sum = (1+n)*n/2; /*
執行第7次
*/sum = (1+n)*n/2; /*
執行第8次
*/sum = (1+n)*n/2; /*
執行第9次
*/sum = (1+n)*n/2; /*
執行第10次
*/printf("%d
",sum); /*
執行一次
*/
上面的兩段**中,其實無論n有多少個,本質是是3次和12次的執行差異。這種與問題的大小無關,執行時間恆定的演算法,成為具有o(1)的時間複雜度,又叫做常數階。
注意:不管這個常數是多少,3或12,都不能寫成o(3)、o(12),而都要寫成o(1),這一點要特別注意。
此外,對於分支結構而言,無論真假執行的次數都是恆定不變的,不會隨著n的變大而發生變化,所以單純的分支結構(不在迴圈結構中),其時間複雜度也是o(1)。
3.2線性階
線性階的迴圈結構會複雜一些,要確定某個演算法的階次,需要確定特定語句或某個語句集執行的次數。因此要分析演算法的複雜度,關鍵是要分析迴圈結構的運**況。
此時得到時間複雜的為o(n)
inti;for(i = 0 ; i < n ; i++)
3.3平方階
inti;for(i = 0 ; i < n ; i++)
}
上面的程式中,對於對於內層迴圈,它的時間複雜度為o(n),但是它是包含在外層迴圈中,再迴圈n次,因此這段**的時間複雜度為o(n2)。
inti;for(i = 0 ; i < n ; i++)
}
但是,如果內層迴圈改成了m次,時間複雜度就為o(n*m)
再來看一段稍微複雜一點的程式
inti;for(i = 0 ; i < n ; i++)
}
這段**的時間複雜度又是多少呢?
分析一下:外層迴圈執行n次,每執行一次,內層的迴圈次數就比上一次減一
注意:上面的內層迴圈j = i ;而不是0
因為i = 0時,內層迴圈執行了n次,當i=1時,執行了n-1次……當i=n-1時,執行了1次,所以總的執行次數為:
n+(n-1)+(n-1)+...+1 =n(n+1)/2 = n2/2 + n
/2根據大o推導方法,保留最高端項,n2/2 ,然後去掉這個項相乘的常數,1/2
因此,這段**的時間複雜度為o(n2)
3.4對數階
int count = 1;while(count < n)
因為每次count*2後,距離結束迴圈更近了。也就是說有多少個2 相乘後大於n,退出迴圈。
數學公式:2x = n --> x = log2
n因此這個迴圈的時間複雜度為o(logn)
3.5呼叫函式時的時間複雜度計算方法:
inti,j;
void function(int
count)
for(i = 0 ; i < n ; i++)
這個時候就可以直接把函式體放到迴圈內部,然後進行判斷。
函式的時間複雜度是o(1),因此整體的時間複雜度為o(n)。
假如function是這樣的:
void function(intcount)
}
和第乙個的不同之處在於函式體的內容改變了,變成了線性階,所以可以把整體看成平方階,因此最終的時間複雜度為o(n2)
最後看乙個比較複雜的
n++; /*執行次數為1
*/function(n);
/*執行次數為n
*/int
i,j;
for(i = 0 ; i < n ; i++)
for(i = 0 ; i < n ; i++)
}
它的執行次數f(n) = 1 + n + n2 + n(n+1)/2 + 3/2n2+3/2 n+1,
根據推導大o階的方法,最終它的時間複雜度為:o(n2)
執行次數函式
階
術語描述
12o(1)
常數階2n+3
o(n)
線性階3n2+2n+1
o(n2)
平方階5log2
n+20
o(log2
n)對數階
2n+3nlog2
n+19
o(nlogn)
nlog2
n階6n3+2n2+3n+4
o(n3)
立方階2n
o(2n)
指數階時間複雜度所耗費的時間是:
o(1) < o(logn) < o(n) < o(nlogn) < o(n2) < o(n3) n) < o(n!) n)
參考文獻:《大話資料結構》
時間複雜度 大O演算法
演算法的執行效率,就是演算法 的執行時間。我們需要能夠用肉眼就看出一段 的執行時間。int cal int n return sum 2,3行都執行了1個unit time的執行時間,4,5行都執行了n遍,所以是2n unit time的執行時間,所以一共是 2n 2 unit time。所有的 的...
時間複雜度分析 大O記法
就是看乙個程式執行消耗的時間,這個最簡單的分析方法但是有很大的缺點 用這種方式去測試需要等待程式執行完畢,浪費了很多時間在等待程式執行上 對於不同的硬體條件,程式執行的速度都是不一樣的,這樣的結果就沒有說服力 程式設計師主要關注的是 使用什麼演算法實現 乙個問題的規模 設t n 為問題規模n的函式,...
演算法的時間複雜度與大O記法
演算法的時間複雜度 演算法的時間複雜度是乙個關於問題規模n的函式,而且這個函式描述了cpu執行演算法所需要的時間。大o記法 描述時間複雜度優劣的一種記法。2 推導大o階的方法 假設演算法的時間複雜度為t n 1.只保留最高端項 2.將最高端項的常數改為1 第一步 計算語句執行次數t n void m...