演算法的時間複雜度(一)

2021-09-06 17:42:16 字數 4124 閱讀 1079

**:

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

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); /*

執行一次

*/

事實上無論n為多少,上面的兩段**就是3次和12次執行的差異,這種與問題的大小無關(n的多少),執行時間恆定的演算法,我們稱之為具有o(1)的時間複雜度,又叫常數階。

注意,不管這個常數是多少,我們都記作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

int count = 1;2

while (count

3

由於每次count乘以2之後,就距離n更近了一分。也就是說,有多少個2相乘後大於n,則會退出迴圈。由2x=n得到x=log2n。所以這個迴圈的時間複雜度為o(logn)。

2.9.6 平方階

下面的例子是乙個迴圈巢狀,它的內迴圈剛才我們已經分析過,時間複雜度為o(n)。

1

inti,j;

2for(i = 0; i < n; i++)

3

8 }

而對於外層的迴圈,不過是內部這個時間複雜度為o(n)的語句,再迴圈n次。所以這段**的時間複雜度為o(n2)。

如果外迴圈的迴圈次數改為了m,時間複雜度就變為o(m×n)。

1

inti,j;

2for(i = 0; i < m; i++)

3

8 }

所以我們可以總結得出,迴圈的時間複雜度等於迴圈體的複雜度乘以該迴圈執行的次數。

那麼下面這個迴圈巢狀,它的時間複雜度是多少呢?

1

inti,j;

2for(i = 0; i < n; i++)

3

8 }

由於當i = 0時,內迴圈執行了n次,當i = 1時,執行了n-1次,……當i = n-1時,內迴圈執行了1次。所以總的執行次數為

用我們推導大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

void function(int

count)

2

8 }

事實上,這和剛才舉的例子是一樣的,只不過把巢狀內迴圈放到了函式中,所以最終的時間複雜度為o(n2)。

下面這段相對複雜的語句:

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 ...

演算法時間複雜度空間複雜度

演算法 是解決某一類問題的通法,即一系列清晰無歧義的計算指令。每個演算法只能解決具有特定特徵的一類問題,但乙個問題可由多個演算法解決。乙個演算法應該有以下五個方面的特性 比較演算法的優劣我們從兩個維度去進行考量 時間 空間 時間複雜度,空間複雜度 找出基本語句 演算法中執行次數最多的那條語句就是基本...