分析算法時間複雜度的方法

1.1 頻度統計法。算法

頻度統計法指以程序中語句執行次數的多少做爲算法時間度量分析的一種方法。一般狀況下,算法的時間效率主要取決於程序中包含的語句條數和採用的控制結構這二者的綜合效果。所以,最原始且最牢靠的方法是求出全部主要語句的頻度f(n),而後求全部頻度之和。函數

例如:以下形式的語句段:排序

for (i=1;i<n;i++)遞歸

{ y++;數學

for (j=0;j<(2*n);j++)for循環

x++;class

}效率

這個由兩個for語句構成的程序段,外循環的重複執行次數是n-1次,內循環的單趟重複執行次數是2×n次。所以,語句y++的頻度爲n-1,語句x++的頻度爲2×n×(n-1)。變量

因此, T(n)=O(∑f(n))=O(n-1+2×n2-2×n)擴展

取增加最快的一項做爲數量級,則 T(n)=O(n2)

該方法簡單,結果絕對精確,適用於大多數程序。但分析算法時間效率時每每只需計算出其大體數量級,此時,採用頻度估算法便可。

1.2 頻度估算法。

先找出對於所求解的問題來講是共同的原操做,並求出原操做的語句頻度f(n),而後直接以f(n)衡量T(n)。在使用頻度估算法時應注意到一個顯著的標誌,就是原操做每每是最內層循環的循環體,而且,完成該操做所需的時間與操做數的具體取值無關。這種方法比較適合於帶有多重循環的程序。

例如:數學中求兩個矩陣乘法的常規方法是用了一個三重循環,以下:

for (i=1;i<=n;i++)

{ for (j=1;j<=n;j++)

{ c[i][j]=0;

for (k=1;k<=n;k++)

c[i][j]=c[i][j]+a[i][k]*b[k][j];

}

}

這個程序段的原操做是處於最內層循環的語句c[i][j]=c[i][j]+a[i][k]*b[k][j],該語句的重複執行次數即原操做的頻度是n3,能夠直接得出:該算法的時間複雜度T(n)=O(n3)。

對於一些複雜的算法,能夠將算法分解成容易估算的幾個部分,利用頻度估算法分別求出這幾部分的時間複雜度,而後利用求和的原則獲得整個算法的時間複雜度。

頻度估算法的優勢是結果較精確,方法簡單且易掌握,但對於原操做的頻度不易直接肯定的程序,卻無能爲力。

1.3 頻度未知數法。

當不能直接求出原操做的重複執行次數f(n),但經過對程序主要語句的分析,確信能夠經過間接的方式計算得出。其基本規律是:首先將原操做的頻度設爲一個未知數,而後根據原操做執行結束的條件及特徵列方程求出它,若是結果是不等式,取其極大值。

好比程序段: i=s=0;

while (s<n)

{ i++; s+=i; }

分析:該程序段的原操做是語句s+=i,沒法一眼看出原操做的頻度f(n)。爲求得f(n),設循環體共執行了k次後結束,即令f(n)=k,則根據語義,能夠得出

1+2+3+……+k>=n 且 1+2+3+……+(k-1)<n

由以上兩式,可得方程組

取其極值,並忽略常數對數量級的影響,可得 T(n)=O( )=O( )

1.4 列舉頻度概括法。

程序中常常會出現帶有倍增型循環的狀況。倍增循環指內循環的執行次數隨外循環控制變量而變化的多重循環結構。

例如: m=1;

for (i=1;i<=n;i++)

{ m=m*2;

for (j=1;j<=m;j++)

x++;

}

分析:當外循環變量i分別從1,2,……,一直取到n時,內循環的執行次數依次是2,4,8,……,2n,這是一個幾何級數序列,其中每一項的值是前一項的常數倍。

所以,

這種算法的特徵是,原操做的頻度和一個變化的量有關,好比內循環的執行次數依賴於外循環的循環控制變量,或每執行一次循環,循環控制變量將被乘以(除以)一個常數。

再如: for (i=0;i<n;i++)

for (j=i;j<n;j++)

for (k=j;k<n;k++)

x++;

分析:因爲最內層for循環控制語句執行1次,其循環體即原操做x++剛好執行了n-j次,所以,整個算法完成時共執行了 次x++語句,而

結論:當分析帶有倍增循環結構程序的運行時間開銷時,須要把每次執行循環的時間累加起來,其結果表達式每每就被轉化爲一個級數求和的問題。

1.5 頻度指望值法。

當原操做的執行次數不只依賴於問題的規模,並且隨原始數據集狀態的不一樣而不一樣時,每每須要根據原始數據的分佈特色,考慮數據在某種機率分佈下頻度的一個平均值。此時,即便問題規模相同,對於不一樣的特定輸入,其時間開銷也不一樣。

在這種情形下,考慮求符合某種機率分佈狀況下的原操做的平均頻度,而後以平均頻度的一個數量級做爲算法的時間度量。

例如:順序查找算法

int Search_Seq(Table S,KeyType key)

// Table是查找表類型,KeyType表示關鍵字類型

{ S.elem[0].key=key;

for (i=S.length;S.elem[i]!=key;i--);

return i;

}

分析:該算法中的原操做是「將記錄的關鍵字和給定值進行比較」,但根據 for循環的判斷條件,比較的次數取決於待查記錄在查找表中的位置i。根據所查找數據在查找表中位置的不一樣,其時間開銷可能在一個很大的範圍內浮動。爲求出時間複雜度,一般轉而求「其關鍵字和給定值進行過比較的記錄的個數的平均值」,即「比較次數」的平均頻度。通常來講,在進行研究時,爲方便討論,對於經典的查找和排序算法,老是考慮「等機率」條件。

因此,各記錄的查找機率依次爲:

第i個記錄的比較次數 是: =n-i+1

故,平均頻度

因此,T(n)= =O(n)

根據原始數據集的分佈特色,有些查找問題的檢索機率不必定相等,但求解的方法相同,都是求某種機率分佈下的一個指望值。對於原操做的執行次數依賴於原始數據排列狀況的問題來講,內循環體的執行次數取決於外循環控制變量的情形很是常見,其求解方法也徹底適用。例如:大多數靜態的排序算法。

須要說明的一點是:數據分佈的特色對於不少查找算法效率都會有很大的影響,而平均狀況分析並不老是可行。由於,首先要求瞭解清楚數據是如何分佈的。對於這一類問題,有時候要根據各類可能出現的最壞狀況來估算算法的時間複雜度。

1.6 遞歸算法時間複雜度的計算技巧。

遞歸過程的運行時間通常都能經過一個遞歸關係式獲得很好的體現。根據對遞歸關係式的不一樣計算方法,將遞歸算法的求解方法提煉爲以下兩種。

1.6.1擴展遞歸迭代法。

當須要找到一個遞歸問題的精確答案時,可採用一種遞歸擴展技術。其基本方法是:方程右邊較小的項根據定義被依次替代,如此反覆擴展,直到獲得一個沒有遞歸式的完整數列,從而將複雜的遞歸問題轉化爲了新的求和問題。

例如: float fact(long int n)

{ if (n<0) return(-1);

else if (n==0 || n==1) return(1);

else return(n*fact(n-1));

}

分析:遞歸函數fact每遞歸調用自身一次,問題規模就減小1。該函數中出口語句的運行時間爲O(1);調用返回的結果與輸入參數相乘,這個操做的運行時間是一個常量能夠記爲O(1)。所以,函數fact的時間代價就等於該常數加上執行遞歸調用的時間,能夠表示成

C n<=1

T(n)= C爲遞歸調用語句的運行時間,這裏是常數O(1)

則,

=……

因此,函數fact的時間複雜度是O(n)。

利用遞歸自己的特色採用這種擴展技術求解遞歸程序的時間效率,是一種保守且可靠的方法。但有些問題,其求和序列的推導可能會是一項比較繁瑣而枯燥的純數學工做。遇到這種狀況時,徹底可讓我的的經驗充分發揮做用,利用經驗去猜想答案。

1.6.2上下限猜想法。

先試着猜想答案,找出一個認爲是正確的上下限估計,而後再去證實它。若是概括證實成功,那麼再試着收縮上下限;若是證實失敗,那麼就放鬆限制重試;一旦上下限符合要求,就獲得了所求的答案。

例如:如下方程描述歸併排序的運行時間,其數學的推導方法很是繁瑣,現用上下限猜想技術來估算其漸進時間複雜度。

1 n=2

T(n)=

不失通常性,先猜想這個遞歸有一個上限 O(n2),更準確地說,假定T(n)≤n2,經過概括來證實這個假定是否正確。若是正確,繼續收縮上限,猜想一個更小的估計。

爲了使計算簡便,假定n是2的乘方。初始狀況:T(2)=1≤22,顯然成立。

假設當i≤n時 T(i)≤i2 成立,要證實對於全部的n=2N,N≥1,T(n) ≤n2可以獲得T(2n) ≤(2n)2。

而 T(2n)=2T(n)+2n≤2n2+2n≤4n2≤(2n)2 至此命題得證。

因此,猜想T(n)≤O(n2)是正確的。

可是O(n2)多是一個很高的估計。若是猜想更小一些,例如T(n)≤cn(c爲某個常數),很明顯,由於c2n=2cn,沒有爲額外的代價n留下餘地,使待排序的兩塊歸併在一塊兒,所以T(n)≤cn不可能成立。這樣就能夠初步得知,真正的代價必定在cn與n2之間。

繼續嘗試T(n)≤nlog2n。初始狀況: T(2)=1≤(2&#8226;log22)=2。概括假設T(n)≤nlog2n,那麼:T(2n)=2T(n)+2n≤2nlog2n+2n≤2n(log2n+1) ≤2nlog22n

相似地,還能夠證實T(n)≥(nlog2n)。因此,T(n)就是O(nlog2n)。

在求解漸近時間複雜度時,這種猜想技術是一種頗有用的技術,當尋找精確解時,就不適用了。

2. 結束語

提倡在解決問題時,首先要詳細分析算法的特性及特徵,而後再按照不一樣的特性採用合適的方法區別對待,具體問題具體分析,從而避免沒必要要的代價和周折,達到快速而準確求解的目的。

相關文章
相關標籤/搜索