**:
2.9 演算法的時間複雜度
2.9.1 演算法時間複雜度定義
在進行演算法分析時,語句總的執行次數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(n),o(1),o(n2)。我們分別給它們取了非官方的名稱,o(1)叫常數階,o(n)叫線性階,o(n2)叫平方階,當然,還有其他的一些階,我們之後會介紹。
2.9.2 推導大o階方法
那麼如何分析乙個演算法的時間複雜度呢?即如何推導大o階呢?我們給出了下面的推導方法,基本上,這也就是總結前面我們舉的例子
推導大o階1.用常數1取代執行時間中的所有加法常數。
2.在修改後的執行次數函式中,只保留最高端項。
3.如果最高端項存在且不是1,則去除與這個項相乘的常數。
得到的結果就是大o階。
哈,彷彿是得到了遊戲攻略一樣,我們好像已經得到了乙個推導演算法時間複雜度的萬能公式。可事實上,分析乙個演算法的時間複雜度,沒有這麼簡單,我們還需要多看幾個例子。
2.9.3 常數階
首先順序結構的時間複雜度。下面這個演算法,也就是剛才的第二種演算法,為什麼時間複雜度不是o(3),而是o(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句,即:
1事實上無論n為多少,上面的兩段**就是3次和12次執行的差異,這種與問題的大小無關(n的多少),執行時間恆定的演算法,我們稱之為具有o(1)的時間複雜度,又叫常數階。int sum = 0, n = 100; /*
執行一次
*/2 sum = (1+n)*n/2; /*
執行第1次
*/3 sum = (1+n)*n/2; /*
執行第2次
*/4 sum = (1+n)*n/2; /*
執行第3次
*/5 sum = (1+n)*n/2; /*
執行第4次
*/6 sum = (1+n)*n/2; /*
執行第5次
*/7 sum = (1+n)*n/2; /*
執行第6次
*/8 sum = (1+n)*n/2; /*
執行第7次
*/9 sum = (1+n)*n/2; /*
執行第8次
*/10 sum = (1+n)*n/2; /*
執行第9次
*/11 sum = (1+n)*n/2; /*
執行第10次
*/12 printf("
%d",sum); /*
執行一次
*/
注意,不管這個常數是多少,我們都記作o(1),而不能是o(3)、o(12)等其他任何數字。這是初學者常常犯的錯誤。
對於分支結構而言,無論是真,還是假,執行的次數都是恆定的,不會隨著n的變大而發生變化,所以單純的分支結構(不包含在迴圈結構中),其時間複雜度也是o(1)。
2.9.4 線性階
迴圈結構就會複雜很多。要確定某個演算法的階次,我們常常需要確定某個特定語句或某個語句集執行的次數。因此,我們要分析演算法的複雜度,關鍵就是要分析迴圈結構的運**況。
下面這段**,它的迴圈的時間複雜度為o(n)。因為迴圈體中的**須要執行n次。
int i;
for(i = 0; i
2.9.5 對數階
那麼下面的這段**,時間複雜度又是多少呢?
1由於每次count乘以2之後,就距離n更近了一分。也就是說,有多少個2相乘後大於n,則會退出迴圈。由2x=n得到x=log2n。所以這個迴圈的時間複雜度為o(logn)。int count = 1;2
while (count
3
2.9.6 平方階
下面的例子是乙個迴圈巢狀,它的內迴圈剛才我們已經分析過,時間複雜度為o(n)。
1而對於外層的迴圈,不過是內部這個時間複雜度為o(n)的語句,再迴圈n次。所以這段**的時間複雜度為o(n2)。inti,j;
2for(i = 0; i < n; i++)
3
8 }
如果外迴圈的迴圈次數改為了m,時間複雜度就變為o(m×n)。
1所以我們可以總結得出,迴圈的時間複雜度等於迴圈體的複雜度乘以該迴圈執行的次數。inti,j;
2for(i = 0; i < m; i++)
3
8 }
那麼下面這個迴圈巢狀,它的時間複雜度是多少呢?
1由於當i = 0時,內迴圈執行了n次,當i = 1時,執行了n-1次,……當i = n-1時,內迴圈執行了1次。所以總的執行次數為inti,j;
2for(i = 0; i < n; i++)
3
8 }
用我們推導大o階的方法,第一條,沒有加法常數不予考慮;第二條,只保留最高端項,因此保留n2/2;第三條,去除這個項相乘的常數,也就是去除1/2,最終這段**的時間複雜度為o(n2)。
從這個例子,我們也可以得到乙個經驗,其實理解大o推導不算難,難的是對數列的一些相關運算,這更多的是考察你的數學知識和能力,所以想考研的朋友,要想在求演算法時間複雜度這裡不失分,可能需要強化你的數學,特別是數列方面的知識和解題能力。
我們繼續看例子,對於方法呼叫的時間複雜度又如何分析。
int i,j;
for(i = 0; i
上面這段**呼叫乙個函式function。
void function(int count)
函式體是列印這個引數。其實這很好理解,function函式的時間複雜度是o(1)。所以整體的時間複雜度為o(n)。
假如function是下面這樣的:
1事實上,這和剛才舉的例子是一樣的,只不過把巢狀內迴圈放到了函式中,所以最終的時間複雜度為o(n2)。void function(int
count)
2
8 }
下面這段相對複雜的語句:
1 n++; /*它的執行次數執行次數為1
*/2 function(n); /*
執行次數為n*/3
inti,j;
4for(i = 0; i < n; i++) /*
執行次數為n2*/5
8for(i = 0; i < n; i++) /*
執行次數為n(n + 1)/2*/9
14}15
常見的時間複雜度,按數量級遞增排列依次為:
常數階o(1)、
對數階o(log2n)、
線性階o(n)、
線性對數階o(nlog2n)、
平方階o(n^2)、
立方階o(n^3)、
k次方階o(n^k)、
指數階o(2^n)。
演算法時間複雜度 一
演算法時間複雜度的定義 在進行演算法分析時,語句總的執行次數t n 是關於問題規模n的函式,進而分析t n 隨n的變化情況並確定t n 的數量級。演算法的時間複雜度記作 t n o f n f n 是問題規模n的某個函式。執行次數 時間 如何分析乙個演算法的時間複雜度 o階推導法 用常數1取代執行時...
演算法 時間複雜度(一)
概念簡述 明確 舉例分析 理論分析 演算法複雜度分為時間複雜度和空間複雜度。時間複雜度是指執行演算法所需要的計算工作量,在計算機 科學中,演算法的時間複雜度是乙個函式,它定性描述了該演算法的執行時間,是乙個關於代表演算法輸入值 的字串的長度的函式。時間複雜度常用大o符號表述,如 o 1 o n o ...
演算法時間複雜度空間複雜度
演算法 是解決某一類問題的通法,即一系列清晰無歧義的計算指令。每個演算法只能解決具有特定特徵的一類問題,但乙個問題可由多個演算法解決。乙個演算法應該有以下五個方面的特性 比較演算法的優劣我們從兩個維度去進行考量 時間 空間 時間複雜度,空間複雜度 找出基本語句 演算法中執行次數最多的那條語句就是基本...