《大话数据结构》第2章 算法基础 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句,即:
?
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次執行的差異,這種與問題的大小無關(n的多少),執行時間恒定的算法,我們稱之為具有O(1)的時間復雜度,又叫常數階。
??????? 注意,不管這個常數是多少,我們都記作O(1),而不能是O(3)、O(12)等其他任何數字。這是初學者常常犯的錯誤。
??????? 對于分支結構而言,無論是真,還是假,執行的次數都是恒定的,不會隨著n的變大而發生變化,所以單純的分支結構(不包含在循環結構中),其時間復雜度也是O(1)。
2.9.4?線性階
??????? 循環結構就會復雜很多。要確定某個算法的階次,我們常常需要確定某個特定語句或某個語句集運行的次數。因此,我們要分析算法的復雜度,關鍵就是要分析循環結構的運行情況。
??????? 下面這段代碼,它的循環的時間復雜度為O(n)。因為循環體中的代碼須要執行n次。
for(i?=?0;?i?<?n;?i++)
{
???/*時間復雜度為O(1)的程序步驟序列*/
}
2.9.5?對數階
??????? 那么下面的這段代碼,時間復雜度又是多少呢?
int?count?=?1;
while?(count?<?n)
{
???count?=?count?*?2;
???/*時間復雜度為O(1)的程序步驟序列*/
}
??????? 由于每次count乘以2之后,就距離n更近了一分。也就是說,有多少個2相乘后大于n,則會退出循環。由2x=n得到x=log2n。所以這個循環的時間復雜度為O(logn)。
2.9.6?平方階
??????? 下面的例子是一個循環嵌套,它的內循環剛才我們已經分析過,時間復雜度為O(n)。
?
int?i,j;for(i?=?0;?i?<?n;?i++)
{
???for?(j?=?0;?j?<?n;j++)???????????????????????
???{??????????????????????????????????????
???????/*時間復雜度為O(1)的程序步驟序列*/
???}??????????????????????????????????????
}
??????? 而對于外層的循環,不過是內部這個時間復雜度為O(n)的語句,再循環n次。所以這段代碼的時間復雜度為O(n2)。
??????? 如果外循環的循環次數改為了m,時間復雜度就變為O(m×n)。
for(i?=?0;?i?<?m;?i++)
{
???for?(j?=?0;?j?<?n;?j++)????????????????
???{??????????????????????????????????????
???????/*時間復雜度為O(1)的程序步驟序列*/
???}??????????????????????????????????????
}
??????? 所以我們可以總結得出,循環的時間復雜度等于循環體的復雜度乘以該循環運行的次數。
??????? 那么下面這個循環嵌套,它的時間復雜度是多少呢?
int?i,j;
for(i?=?0;?i?<?n;?i++)
{
????for?(j?=?i;?j?<?n;?j++)??/*注意int?j?=?i而不是0*/
????{??????????????????????????????????????
??????????/*時間復雜度為O(1)的程序步驟序列*/
????}??????????????????????????????????????
}
??????????????由于當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?<?n;?i++)
{
???function(i);
}
?
????????????? 上面這段代碼調用一個函數function。
{
???print(count);
}
???????函數體是打印這個參數。其實這很好理解,function函數的時間復雜度是O(1)。所以整體的時間復雜度為O(n)。
?????? 假如function是下面這樣的:
{
???int?j;
???for?(j?=?count;?j?<?n;j++)???????????????????????
???{??????????????????????????????????????
??????/*時間復雜度為O(1)的程序步驟序列*/
???}????
}?
??????? 事實上,這和剛才舉的例子是一樣的,只不過把嵌套內循環放到了函數中,所以最終的時間復雜度為O(n2)。
??????? 下面這段相對復雜的語句:
function(n);?????/*執行次數為n*/
int?i,j;?????
for(i?=?0;?i?<?n;?i++)??/*執行次數為n2*/
{
???function?(i);
}
for(i?=?0;?i?<?n;?i++)??/*執行次數為n(n?+?1)/2*/
{
???for?(j?=?i;j?<?n;?j++)???????????????????????
???{??????????????????????????????????????
????????/*時間復雜度為O(1)的程序步驟序列*/
???}??????????????????????????????????????
}
?
???????? 它的執行次數 ,根據推導大O階的方法,最終這段代碼的時間復雜度也是O(n2)。
出處:http://www.cnblogs.com/cj723/archive/2011/03/05/1971640.html
總結
以上是生活随笔為你收集整理的《大话数据结构》第2章 算法基础 2.9 算法的时间复杂度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《大话数据结构》第2章 算法基础 2.8
- 下一篇: 《大话数据结构》第3章 线性表 3.8.