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

2021-10-09 23:03:42 字數 3050 閱讀 2583

一、演算法執行時間需通過依據該演算法編制的程式在計算機上執行時所消耗的時間來度量。而度量乙個程式的執行時間通常有兩種方法。

(1)事後統計的方法

這種方法可行,但不是乙個好的方法。該方法有兩個缺陷:一是要想對設計的演算法的執行效能進行評測,必須先依據演算法編制相應的程式並實際執行;二是所得時間的統計量依賴於計算機的硬體、軟體等環境因素,有時容易掩蓋演算法本身的優勢。

(2)事前分析估算的方法

因事後統計方法更多的依賴於計算機的硬體、軟體等環境因素,有時容易掩蓋演算法本身的優劣。因此人們常常採用事前分析估算的方法。

二、時間複雜度

1、基本操作執行次數=時間頻度

乙個演算法中的語句執行次數稱為語句頻度或時間頻度。記為t(n)。

例如:給小灰一條長10寸的麵包,小灰每3天吃掉1寸,那麼吃掉整個麵包需要幾天?

答案自然是 3 x 10 = 30天。

如果麵包的長度是 n 寸呢?

此時吃掉整個麵包,需要 3 x n = 3n 天。

如果用乙個函式來表達這個相對時間,可以記作 t(n) = 3n,執行次數是線性的。

void eat1(

int n)

}

2、時間複雜度

一般情況下,演算法中基本操作重複執行的次數是問題規模n的某個函式,用t(n)表示,若有某個輔助函式f(n),使得當n趨近於無窮大時,t(n)/f(n)的極限值為不等於零的常數,則稱f(n)是t(n)的同數量級函式。記作t(n)=o(f(n)),稱o(f(n)) 為演算法的漸進時間複雜度,簡稱時間複雜度。漸進時間複雜度用大寫o來表示,所以也被稱為大o表示法。

如何推導出時間複雜度呢?有如下幾個原則:

(1)如果執行時間是常數量級,用常數1表示;

(2)只保留時間函式中的最高端項;

(3)如果最高端項存在,則省去最高端項前面的係數。

①常數階

int

sum=

0, n =

100;

printf(「i love you.com\n」)

;printf(「i love you.com\n」)

;printf(「i love you.com\n」)

;printf(「i love you.com\n」)

;printf(「i love you.com\n」)

;printf(「i love you.com\n」)

;sum=(

1+n)

*n/2

;

第一條就說明了所有加法常數給他個o(1)即可

②線性階:一般含有非巢狀迴圈涉及線性階,線性階就是隨著問題規模n的擴大,對應計算次數呈直線增長。

int i , n =

100,

sum=0;

for( i=

0; i < n; i++)

上面這段**,它的迴圈的時間複雜度為o(n),因為迴圈體中的**需要執行n次。

③平方階

int i, j, n =

100;

for( i=

0; i < n; i++)

}

n等於100,也就是說外層迴圈每執行一次,內層迴圈就執行100次,那總共程式想要從這兩個迴圈出來,需要執行100*100次,也就是n的平方。所以這段**的時間複雜度為o(n^2)。

④對數階

int i =

1, n =

100;

while

( i < n )

由於每次i*2之後,就距離n更近一步,假設有x個2相乘後大於或等於n,則會退出迴圈。

於是由2^x = n得到x = log(2)n,所以這個迴圈的時間複雜度為o(logn)。

常用的時間複雜度所耗費的時間從小到大依次是:

二、最壞情況與平均情況

我們查詢乙個有n個隨機數字陣列中的某個數字,最好的情況是第乙個數字就是,那麼演算法的時間複雜度為o(1),但也有可能這個數字就在最後乙個位置,那麼時間複雜度為o(n)。平均執行時間是期望的執行時間。最壞執行時間是一種保證。在應用中,這是一種最重要的需求,通常除非特別指定, 大o表示法是用來表示乙個演算法在最糟糕情況下的執行時間。

這裡就又涉及到大o的定義,「因為大o就是資料量級突破乙個點且資料量級非常大的情況下所表現出的時間複雜度,這個資料量也就是常數項係數已經不起決定性作用的資料量」。

例如上圖中20就是那個點,n只要大於20 常數項係數已經不起決定性作用了。

「所以我們說的時間複雜度都是省略常數項係數的,是因為一般情況下都是預設資料規模足夠的大,基於這樣的事實,給出的演算法時間複雜的的乙個排行如下所示」:

o(1)常數階 < o(logn)對數階 < o(n)線性階 < o(n^2)平方階 < o(n^3)(立方階) < o(2^n) (指數階)

但是也要注意大常數,如果這個常數非常大,例如10^7 ,10^9 ,那麼常數就是不得不考慮的因素了。

四、演算法的空間複雜度

我們在寫**時,完全可以用空間來換去時間。

舉個例子說,要判斷某年是不是閏年,你可能會花一點心思來寫乙個演算法,每給乙個年份,就可以通過這個演算法計算得到是否閏年的結果。

另外一種方法是,事先建立乙個有2050個元素的陣列,然後把所有的年份按下標的數字對應,如果是閏年,則此陣列元素的值是1,如果不是元素的值則為0。這樣,所謂的判斷某一年是否為閏年就變成了查詢這個陣列某乙個元素的值的問題。

第一種方法相比起第二種來說很明顯非常節省空間,但每一次查詢都需要經過一系列的計算才能知道是否為閏年。第二種方法雖然需要在記憶體裡儲存2050個元素的陣列,但是每次查詢只需要一次索引判斷即可。

這就是通過一筆空間上的開銷來換取計算時間開銷的小技巧。到底哪一種方法好?其實還是要看你用在什麼地方。

通常,我們都是用「時間複雜度」來指執行時間的需求,是用「空間複雜度」指空間需求。

當直接要讓我們求「複雜度」時,通常指的是時間複雜度。

顯然對時間複雜度的追求更是屬於演算法的潮流!

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

1 時間複雜度 1 時間頻度 乙個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時間多,哪個演算法花費的時間少就可以了。並且乙個演算法花費的時間與演算法中語句的執行次數成正比例,哪個演算法中語句執行次數...

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

演算法複雜度 時間複雜度和空間複雜度 關鍵字 演算法複雜度 時間複雜度 空間複雜度 1 時間複雜度 1 時間頻度 乙個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時 間多,哪個演算法花費的時間少就可以...

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

演算法的時間複雜度是指執行演算法所需要的計算工作量。n稱為問題的規模,當n不斷變化時,時間頻度t n 也會不斷變化。但有時我們想知道它變化時呈現什麼規律。為此,我們引入時間複雜度概念。一般情況下,演算法中基本操作重複執行的次數是問題規模n的某個函式,用t n 表示,若有某個輔助函式f n 存在乙個正...