時間複雜度和空間複雜度

2021-10-14 18:31:41 字數 3087 閱讀 9489

最近在看一些與演算法有關的書,了解到時間複雜度和空間複雜度這兩個詞,平時在討論工作時也會提價到,就把概念記錄一下,以後忘記了也方便隨時查閱。畢竟好記性不如爛筆頭。

假如a和b同時實現乙個功能,其中a提交的**執行一次要100ms,占用記憶體5m,而b提交的**執行一次要10s,占用記憶體500m。雖然a和b都實現了功能,但是b的**執行的時間和占用的空間都比a**執行鎖消耗的資源要多,這是不能忍受的。由此可見,執行時間的長短和占用記憶體空間的大小是衡量乙個程式好壞的重要因素。

怎麼能確定**的執行時間呢?

受執行環境和輸入規模等各種因素的影響,**的絕對執行時間是無法預估的。但是我們可以預估**的基本操作執行次數。

場景1:給a乙個長度為10cm的麵包,a每3分鐘吃掉1cm,那麼吃完整個麵包需要多久?

答案是3x10=30分鐘

如果麵包的長度為n cm呢?

此時吃掉整個麵包需要3乘以n即3n分鐘。用乙個函式來表示吃掉整個麵包的所需要的時間,可以記作t(n)=3n,n為麵包的長度

場景2:給a乙個長度為16cm的麵包,a每5分鐘吃掉麵包剩餘長度的一半,即第5分鐘吃到8cm,第10分鐘吃到4cm,以此類推。那麼a把整個麵包吃得只剩1cm,需要多久?

這個問題用數學的表達方式就是數字16不斷的除以2,那麼除幾次過後的結果等於1?。這裡用數學中的對數,即以2為底16的對數log216。因此,把麵包吃得只剩1cm,需要5xlog216即20分鐘。

如果麵包的長度為n cm呢?

此時吃掉整個麵包需要5乘以log2n即5log2n分鐘,可以記作t(n)=5log2n

場景3:給a乙個長10cm的麵包和乙個雞腿。a每2分鐘吃掉乙個雞腿。那麼吃完整個雞腿需要多少時間?

答案當然是2分鐘,這裡和10cm的麵包沒有關係。

如果麵包的長度為n cm呢?

無論麵包多長,吃掉雞腿的時間都是2分鐘,記作t(n)=2

場景4:給a乙個長度為10cm的麵包,a吃掉第乙個1cm需要1分鐘,吃掉第二個1cm需要2分鐘,吃掉第三個1cm需要3分鐘,沒吃掉1cm所花的時間都比上乙個1cm多用1分鐘。那麼吃掉整個麵包都需要多久?

答案是1到10的和,也就是55分鐘

如果麵包的長度為n cm呢?

根據高斯演算法,吃掉整個麵包需要1+2+3+4+5+…+(n-1)+n,即(1+n)xn/2分鐘,也就是0.5n2+0.5n,記作t(n)=0.5n2+0.5n

上述思想同樣適用於程式基本操作執行次數的統計。設t(n)為程式基本操作執行次數的函式(也可以認為是程式的相對執行時間函式),n為輸入規模,以上4種場景對應程式的4中執行方式。

有了基本操作執行次數函式t(n),分析和比較**的執行時間還是有點困難的。如函式a的執行次數是t(n)=100n,函式b的執行次數是t(n)=5n2,看這兩個函式的執行時間就要看n的取值了,為了解決時間分析的難題,就有了漸進時間複雜度(asymptotic time complexity)

漸進時間複雜度

若存在函式f(n),使得當n的值趨近於無窮大時,t(n)/f(n)的極限值為不等於0的常數,則稱f(n)是t(n)的同數量級函式。記作t(n)=o(f(n)),稱為o(f(n)),o為演算法的漸進時間複雜度,簡稱時間複雜度。因為漸進時間複雜度用大寫o來表示,所以也被稱為大o表示法

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

如果執行時間是常數量級,則用常數1表示只保留時間函式中的最高端項如果最高端項存在,則省去最高端項前面的係數

上述4個場景舉例:

當n的值足夠大時,不難判斷出:o(1) < (log2n) < o(n) < o(n2),當然還有各種各樣的演算法,也還有不同形式的時間複雜度。

##空間複雜度

和時間複雜度類似,空間複雜度是對乙個演算法咱執行過程中臨時占用儲存空間大小的量度,它同樣使用了大o表示法,程式占用空間大小的計算公式記作s(n)=o(f(n)),其中n為問題的規模,f(n)為演算法所佔儲存空間的函式。

常見的空間複雜度有以下幾種情況:

常量空間

當演算法的儲存空間大小固定,和輸入規模沒有直接的關係時,空間複雜度記作o(1),例如:

void

method

(int n)

線性空間

當演算法分配的空間是乙個線性的集合(如陣列),並且集合大小和輸入規模n成正比,空間複雜度記作o(n),例如:

void

method

(int n)

二維空間

當演算法空間分配的是乙個二位陣列結婚,並且集合的長度和寬度都與輸入規模n成正比時,空間複雜度記作o(n2),例如:

void

method

(int n)

遞迴空間

遞迴是乙個比較特殊的場景,雖然遞迴**中沒有顯示的宣告變數或集合,但是計算機在執行程式時,會專門分配一塊記憶體,用來儲存「方法呼叫棧」。方法呼叫棧包括進棧和出棧兩個行為。當進入乙個新方法是,執行入棧操作,把呼叫的方法和引數資訊壓入棧中。當方法返回時,執行出棧操作,把呼叫的方法和引數資訊從棧中彈出。執行遞迴操作所需要的記憶體空間和遞迴深度成正比,純粹遞迴操作的空間複雜度也是線性的,如果遞迴的深度是n,那麼空間複雜度就是o(n)。

之所以花大力氣去評估演算法的時間複雜度和空間複雜度,根本原因是計算機的運算速度和空間資源是有限的。魚和熊掌不可兼得,我們必須要在時間複雜度和空間複雜度中選其一。在大多數情況下,時間複雜度更為重要,日益急促的生活節奏下,人們已經不再習慣等待。

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

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

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

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

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

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