python 程式的計算代價(複雜度)

2022-09-13 23:48:29 字數 3482 閱讀 3303

在考慮 python 程式的時間開銷時,有乙個問題特別需要注意:python 程式中的很多基本操作不是常量時間的。

下面是一些情況:

1)基本算術運算時常量時間操作【注:】,邏輯運算時常量時間運算。

2)組合物件的操作有些是常量時間的,有些不是,例如:

① 複製和切片操作通常需要線性時間(與長度有關,是 o(n))時間操作。

② list 和 tuple 的元素訪問和元素賦值,是常量時間的。

③ dict 操作的情況比較複雜【補充乙個鏈結位址】。

3)字串也應該看作組合物件,但許多操作不是常量時間的。

4)建立物件也需要付出空間和時間,空間和時間代價都與物件大小有關。

對於組合物件,這裡可能有需要構造的乙個個元素,元素有大小問題,

整體看還有元素個數問題。通常應看作線性時間和線性空間操作(以元素個數作為規模)。

python 結構和操作的效率問題:

1)構造新結構,如構造 list ,set 等。構造新的空結構(空表,空集合等)是常量時間操作,

而構造乙個包含 n 個元素的結構,則至少需要 o(n) 時間。統計說明,分配長度為 n 個

元素的儲存塊的時間代價是 o(n)。

2)一些 list 操作的效率:表元素訪問的元素修改是常量時間操作,但一般的加入、

刪除元素操作(即使只加入乙個元素)都是 o(n) 時間操作。

3) 字典 dict 操作的效率:主要操作是加入新的鍵值對和基於鍵查詢關聯值。

它們的最壞情況複雜度是 o(n) ,但平均複雜度是 o(l) 。

也就是說,一般而言字典操作的效率很高,但偶然也會出現效率低的情況。

在程式裡使用任何型別的物件,都需要付出空間的代價。建立乙個表或者元組,至少要占用元素個數那麼多的空間。

如果乙個表的元素個數與問題規模線性相關,建立它的空間付出至少為 o(n) (如果元素也是新建立的,還需考慮元素本身的儲存開銷)。

需要注意兩點:

1)python 的各種組合資料物件都沒有預設的最大元素個數。在實際使用中,這些結構能根據元素個數的增長自動擴充儲存空間。

從空間占用的角度看,其實際開銷在存續期間可能變大,但通常不會自動縮小(即使後來元素變得很少了)。

2)還應該注意 python 自動儲存管理系統的影響。舉個例子:如果在程式裡建立了乙個表,此後一直將其作為某個全域性變數的值,

這個物件就會始終存在並占用儲存空間。如果將其作為某個函式裡區域性變數的值,或者雖然作為全域性變數的值,但後來通過

賦值將其拋棄,這個表物件就可以被**。

乙個簡單的例子。假設需要把得到的一系列資料存入乙個表,其中得到乙個資料是 o(l) 常量時間操作。**如下:

data =

whille 還有資料:

x =下一資料

data.insert(0,x)

#把所有資料加在表的前面

或者寫為:

data =

while

還有資料:

x =下一資料

data.insert(len(data),x)

#

前一程式段需要 o(n) 的時間才能完成工作,而後乙個程式段只需要 o(n) 時間。造成這種情況與 list 的實現方式有關。

另乙個例子,建立乙個表,其中包含從 0 到 10000 x n - 1 的整數值:

#

先編寫乙個計算時間的裝飾器

import

time

deftimer(test):

def inner(*args):

start =time.time()

test(*args)

end = time.time() -start

print

(end)

return

inner

@timer

deftest1(n):

lst =

for i in range(n*10000):

lst = lst +[i]

return

lsttest1(5) #

3.522050380706787

@timer

deftest2(n):

lst =

for i in range(n*10000):

return

lsttest2(5) #

0.004010200500488281

@timer

deftest3(n):

return [i for i in range(n*10000)]

test3(5) #

0.0020058155059814453

@timer

deftest4(n):

return list(range(n*10000))

test4(5) #

0.001033782958984375

view code

測試環境為小公尺 pro 15.6 筆記本【i5處理器】。

試著嘗試變化 n 值檢視不同函式的增長趨勢。

設計乙個演算法,通過對它的分析可能得到抽象演算法的時間與空間複雜度。

進而,採用某個變成語言可以做出該演算法的實現。

那麼問題來了,演算法的實現(程式)的時間開銷與原演算法的時間複雜度之間有什麼關係?

理想情況是:

作為演算法的實現,相應程式的時間開銷增加趨勢應該達到原演算法的時間複雜度。但是,如果實現做得不好,其實現程式也可能比這差。

前一話題就有這樣的例子,例如函式 test1 :最常見的錯誤做法就是毫無必要地構造一些可能很大的複雜結構。

例如在遞迴定義的函式裡的遞迴呼叫中構造複雜的結構(如 list 等),而後只使用其中的個別元素。

從區域性看,這樣做使得常量時間的操作變成了線性時間操作。

但從遞迴演算法的全域性看,這種做法經常會使多項式時間演算法變成指數時間演算法。

也就是說,把原來有用的演算法變成了基本無用的演算法。

儲存技術複雜性的代價

如今,我們處於前所未有的變化的時代。其中大部分變化都是由資料驅動的。幸運的是,新的儲存解決方案正在幫助企業管理快速的資料增長,來自新的資料來源的輸入,以及使用資料的新途徑。這些技術可以滿足各種應用需求。雲儲存提供更高的靈活性,並節省成本,ssd固態硬碟和nvme快閃儲存器解決了快速響應時間的需求,網...

程式的時間複雜度計算

很多時候一眼就能看出程式的時間複雜度,但是遇到複雜的就需要將其過程推導出來,為此總結以下兩種形式 一 迴圈主體中的變數參與迴圈條件的判斷 找出主體語句中與t n 成 正比的迴圈變數,帶入進行計算,例如 int i 1 while i n i i 2 其中i 2的次數與t n 成正比,則2的t n 次...

python複雜程式的組織講座

當程式簡單時,將 寫進乙個檔案即可。但當專案的複雜度增加時,會出現 過多導致檔案過大的問題。因此,模組和包就能方便管理和維護 模組和包都是複雜程式組織的一種方式,一般來說,一般複雜度較低使用模組 module 複雜度較高使用包 package 來管理 乙個包 package 可以由多個模組組成,乙個...