時間複雜度&空間複雜度
時間複雜度
算法執行時間需通過依據該算法編制的程序在計算機上運行時所消耗的時間來度量。一般有兩種方法:
- 事後統計:利用計算機的計時功能。有明顯的兩種缺點,一、必須要運行起來才行。二、結果依賴於計算機硬件、軟件環境,容易掩蓋算法本身的優劣。所以該方法一半不可靠,多用後面一種方式。
- 事前分析:一個程序在計算機上運行所消耗的時間取決於下列因素:
- 算法選用的策略。
- 問題規模。
- 書寫程序的語言,實現語言級別越高,執行效率越低。
- 編譯程序所產生的機器代碼的質量。
- 機器執行指令的速度。
顯然,同一個算法用不同的語言實現,或者用不同的編譯程序進行編譯,或者在不同的計算機上運行時,效率均不同。這表明使用絕對的時間單位衡量算法的效率是不合適的。撇開這些與計算機硬件、軟件相關的因素,可以認爲一個特定算法運行工作量的大小,只依賴於問題的規模(通常用整數n表示),或者說,它是問題規模的函數。
一個算法是由控制結構(順序、分之和循環3中)和原操作(指固有數據類型的操作)構成的,則算法取決於兩者的綜合效果。爲了便於比較同一問題的不同算法,從算法中選取一種對於所研究的問題來說是基本操作的原操作,以該基本操作重複執行的次數作爲算法的時間度量。
例如,在如下所示的兩個 矩陣相乘的算法中,"乘法"運算是"矩陣相乘問題"的基本操作。整個算法的執行時間與該基本操作(乘法)重複執行的次數 成正比,記作。
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
c[i][j] = 0;
for (int k = 1; k <= n; ++k) {
c[i][j] += a[i][k] * b[k][j]; // 基本操作(原操作)
}
}
}
一般情況下,算法中基本操作重複執行的次數是問題規模的某個函數,算法的時間度計作
它表示隨着問題規模的增大,算法執行時間的增長率和的增長率相同,被稱作算法的漸進時間複雜度,簡稱時間複雜度。
被稱作問題的基本操作的原操作應該起重複執行次數和算法的執行時間成正比的原操作,多數情況下是深層循環語句中的原操作。它的執行次數和包含他的語句的頻度相同。語句的頻度是指該語句重複執行的次數,例如,在下列3個程序中:
(a) {++x; s = 0;}
(b) for (i = 1; i <= n; ++i) {++x; s+=x};
(c) for (j = 1; j <= n; ++j)
for (k = 1; k <= n; ++k) {++x; s += x;}
含基本操作的語句頻度分別爲1、n和,則這三個程序段的時間複雜度分別爲、、,分別稱爲常量階、線性階和平方階。我們應該儘可能選用多項式階的算法,而不希望用指數階的算法。
由於算法的時間複雜度考慮的只是對於問題規模的增長率,則在南藝精確計算基本操作執行次數的情況下,只需要求出它關於的增長率或者階即可。
有的情況下,算法中基本操作重複執行的次數還隨着問題的輸入數據集不同而不同,因爲各種輸入數據集出現的概率難以確定,算法的時間複雜度也就難以確定。因此,可行的辦法是討論算法在最壞情況下的時間複雜度。一般而言,我們說的時間複雜度都是最壞情況下的時間複雜度。
空間複雜度
類似於算法的時間複雜度,空間複雜度是算法所需存儲空間的度量,計作:
其中爲問題的規模。一個執行的程序除了需要存儲空間來寄存本身所用指令、常數、變量和輸入數據外,也需要一些對數據進行操作的工作單元和存儲一些爲實現計算所需信息的輔助空間。如果輸入數據所佔空間指取決於問題本身,和算法無關,則只需要分析除輸入和程序之外的額外空間,否則應同時考慮輸入本身所需空間(和輸入的表現形式無關)。若額外空間相對於輸入數據量來說是常熟,則稱此算法爲原地工作。