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

2022-07-09 12:54:09 字數 4051 閱讀 4724

**:

在進行演算法分析時,語句總的執行次數t(n)是關於問題規模n的函式,進而分析t(n)隨n的變化情況並確定t(n)的數量級。演算法的時間複雜度,也就是演算法的時間量度。記作:t(n)=o(f(n))。它表示隨問題n的增大,演算法執行時間的增長率和f(n)的增長率相同,稱作演算法的漸進時間複雜度,簡稱為時間複雜度。其中,f(n)是問題規模n的某個函式。

這樣用大寫o()來體現演算法時間複雜度的記法,我們稱之為大0記法

1、用常數1取代執行時間中的所有加法常數。

2、在修改後的執行次數函式中,只保留最高端項。

3、如果最高端項存在且不是1,則去除與這個專案相乘的常數。得到的結果就是大o階。

首先順序結構的時間複雜度。下面這個演算法,是利用高斯定理計算1,2,……n個數的和。

1

int sum = 0, n = 100; /*

執行一次*/2

3 sum = (1 + n) * n / 2; /*

執行一次*/4

5 printf("

%d",sum); /*

執行一次

*/

這個演算法的執行次數函式是f (n)  =3。 根據我們推導大0階的方法,第一步就是把常數項3 改為1。在保留最高端項時發現,它根本沒有最高端項,所以這個演算法的時間複雜度為0(1)

另外,我們試想一下,如果這個演算法當中的語句 sum = (1+n)*n/2;

有10 句,則與示例給出的**就是3次和12次的差異。這種與問題的大小無關(n的多少),執行時間恆定的演算法,我們稱之為具有o(1)的時間複雜度,又叫常數階。對於分支結構而言,無論是真,還是假,執行的次數都是恆定的,不會隨著n 的變大而發生變化,所以單純的分支結構(不包含在迴圈結構中),其時間複雜度也是0(1)。線性階的迴圈結構會複雜很多。要確定某個演算法的階次,我們常常需要確定某個特定語句或某個語句集執行的次數。因此,我們要分析演算法的複雜度,關鍵就是要分析迴圈結構的運**況。

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

1

inti; 23

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

如下**:

1

int count = 1; 2

3while (count

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

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

1inti, j; 23

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

1011 }

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

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

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

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

1

inti, j; 23

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

1011 }

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

用我們推導大o階的方法,第一條,沒有加法常數不予考慮;第二條,只保留最高端項,因此保留時(n^2)/2; 第三條,去除這個項相乘的常數,也就是去除1/2,最終這段**的時間複雜度為o(n2)。

從這個例子,我們也可以得到乙個經驗,其實理解大0推導不算難,難的是對數列的一些相關運算,這更多的是考察你的數學知識和能力。

下面例子是乙個三重迴圈巢狀。

1

inti, j; 23

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

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

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

這裡迴圈了(1^2+2^2+3^2+……+n^2) = n(n+1)(2n+1)/6次,按照上述大o階推導方法,時間複雜度為o(n^3)。

常見的時問複雜度如表所示。

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

我們前面已經談到了。o(1)常數階、o(logn)對數階、o(n)線性階、 o(n^2)平方階等,像o(n^3),過大的n都會使得結果變得不現實。同樣指數階o(2^n)和階乘階o(n!)等除非是很小的n值,否則哪怕n 只是100,都是噩夢般的執行時間。所以這種不切實際的演算法時間複雜度,一般我們都不去討論。

我們查詢乙個有n 個隨機數字陣列中的某個數字,最好的情況是第乙個數字就是,那麼演算法的時間複雜度為o(1),但也有可能這個數字就在最後乙個位置上待著,那麼演算法的時間複雜度就是o(n),這是最壞的一種情況了。

最壞情況執行時間是一種保證,那就是執行時間將不會再壞了。 在應用中,這是一種最重要的需求, 通常, 除非特別指定, 我們提到的執行時間都是最壞情況的執行時間。

而平均執行時間也就是從概率的角度看, 這個數字在每乙個位置的可能性是相同的,所以平均的查詢時間為n/2次後發現這個目標元素。平均執行時間是所有情況中最有意義的,因為它是期望的執行時間。也就是說,我們執行一段程式**時,是希望看到平均執行時間的。可現實中,平均執行時間很難通過分析得到,一般都是通過執行一定數量的實驗資料後估算出來的。一般在沒有特殊說明的情況下,都是指最壞時間複雜度

我們在寫**時,完全可以用空間來換取時間,比如說,要判斷某某年是不是閏年,你可能會花一點心思寫了乙個演算法,而且由於是乙個演算法,也就意味著,每次給乙個年份,都是要通過計算得到是否是閏年的結果。 還有另乙個辦法就是,事先建立乙個有2050個元素的陣列(年數略比現實多一點),然後把所有的年份按下標的數字對應,如果是閏年,此陣列項的值就是1,如果不是值為0。這樣,所謂的判斷某一年是否是閏年,就變成了查詢這個陣列的某一項的值是多少的問題。此時,我們的運算是最小化了,但是硬碟上或者記憶體中需要儲存這2050個0和1。這是通過一筆空間上的開銷來換取計算時間的小技巧。到底哪乙個好,其實要看你用在什麼地方。

演算法的空間複雜度通過計算演算法所需的儲存空間實現,演算法空間複雜度的計算公式記作:s(n)= o(f(n)),其中,n為問題的規模,f(n)為語句關於n所佔儲存空間的函式。

一般情況下,乙個程式在機器上執行時,除了需要儲存程式本身的指令、常數、變數和輸入資料外,還需要儲存對資料操作的儲存單元,若輸入資料所佔空間只取決於問題本身,和演算法無關,這樣只需要分析該演算法在實現時所需的輔助單元即可。若演算法執行時所需的輔助空間相對於輸入資料量而言是個常數,則稱此演算法為原地工作,空間複雜度為0(1)。

通常, 我們都使用"時間複雜度"來指執行時間的需求,使用"空間複雜度"指空間需求。當不用限定詞地使用"複雜度'時,通常都是指時間複雜度。

t(n,m) = t1(n) + t2(m) = o(max)

t(n,m) = t1(n) * t2(m) = o(max)

複雜度與時間效率的關係:

c(常數) < logn < n < n*logn < n^2 < n^3 < 2^n < 3^n < n!

l------------------------------l--------------------------l--------------l

較好                          一般                    較差

參考:《大話資料結構》

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

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

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

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

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

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