我們知道,時間複雜度和「大o表示法」是我們經常會碰到的概念,它們是用來衡量演算法優劣的度量,那具體怎麼算的呢?來看一下
在丟擲概念之前,咱先來個例子:
如果 a+b+c=1000,且 a^2+b^2=c^2(a,b,c 為自然數),如何求出所有a、b、c可能的組合?
第一次計算:
import time
start_time = time.time()
# 注意是三重迴圈
for a in range(0, 1001):
for b in range(0, 1001):
for c in range(0, 1001):
if a**2 + b**2 == c**2 and a+b+c == 1000:
print("a, b, c: %d, %d, %d" % (a, b, c))
end_time = time.time()
print("完成!")
a, b, c: 0, 500, 500
a, b, c: 200, 375, 425
a, b, c: 375, 200, 425
a, b, c: 500, 0, 500
完成!
第二次簡化計算:
import time
start_time = time.time()
# 注意是兩重迴圈
for a in range(0, 1001):
for b in range(0, 1001-a):
c = 1000 - a - b
if a**2 + b**2 == c**2:
print("a, b, c: %d, %d, %d" % (a, b, c))
end_time = time.time()
print("完成!")
執行結果
a, b, c: 0, 500, 500
a, b, c: 200, 375, 425
a, b, c: 375, 200, 425
a, b, c: 500, 0, 500
完成!
即:對於同一問題,我們給出了兩種解決演算法,在兩種演算法的實現中,我們對程式執行的時間進行了測算,發現兩段程式執行的時間相差懸殊(214.583347秒相比於0.182897秒),由此我們可以得出結論:實現演算法程式的執行時間可以反應出演算法的效率,即演算法的優劣。
我們將計算耗時稱絕對耗時,
絕對耗時 = 演算法的執行步驟 * 每一步的cpu耗時
所以單純依靠執行的時間來比較演算法的優劣並不一定是客觀準確的!那麼如何去評價乙個演算法的優劣?
我們假定計算機執行演算法每乙個基本操作的時間是固定的乙個時間單位,那麼有多少個基本操作就代表會花費多少時間單位。顯然對於不同的機器環境而言,確切的單位時間是不同的,但是對於演算法進行多少個基本操作(即花費多少時間單位)在規模數量級上卻是相同的,由此可以忽略機器環境的影響而客觀的反應演算法的時間效率。
對於演算法的時間效率,我們可以用「大o表示法」來表示。
「大o表示法」:對於單調的整數函式f,如果存在乙個整數函式g和實常數c>0,使得對於充分大的n總有f(n)<=c*g(n),就說函式g是f的乙個漸近函式(忽略常數),記為f(n)=o(g(n))。也就是說,在趨向無窮的極限意義下,函式f的增長速度受到函式g的約束,亦即函式f與函式g的特徵相似。
時間複雜度:假設存在函式g,使得演算法a處理規模為n的問題示例所用時間為t(n)=o(g(n)),則稱o(g(n))為演算法a的漸近時間複雜度,簡稱時間複雜度,記為t(n)
結合上面的例子,再來看一下:(演算法執行步驟計算:加減乘除和及邏輯運算每個都可以看做一步,總共為9次)
第二個演算法:
對應的圖如下:
大o表示法:對於演算法進行特別具體的細緻分析雖然很好,但在實踐中的實際價值有限。對於演算法的時間性質和空間性質,最重要的是其數量級和趨勢,這些是分析演算法效率的主要部分。而計量演算法基本運算元量的規模函式中那些常量因子可以忽略不計。例如,可以認為3n2和100n2屬於同乙個量級,如果兩個演算法處理同樣規模例項的代價分別為這兩個函式,就認為它們的效率「差不多」,都為n2級。簡單而言,即將演算法的所有步驟轉換為代數項,然後排除不會對問題的整體複雜度產生較大影響的較低階常數和係數。
時間複雜度:問題規模在正向變化的趨勢下,乙個演算法那耗時的變化趨勢(這個趨勢用乙個曲線表示)該曲線表示的就是該演算法的時間複雜度
分析演算法時,存在幾種可能的考慮:
演算法完成工作最少需要多少基本操作,即 **最優時間複雜度**
演算法完成工作最多需要多少基本操作,即 **最壞時間複雜度**
演算法完成工作平均需要多少基本操作,即 **平均時間複雜度**
往往關注最壞時間複雜度基本操作(如基本加減乘除、邏輯運算):即只有常數項,認為其時間複雜度為o(1)
順序結構(如上下語句即時間複雜度相加):時間複雜度按加法進行計算
迴圈結構(如 for 迴圈):時間複雜度按乘法進行計算
分支結構(如判斷 if-else ):時間複雜度取最大值
判斷乙個演算法的效率時,往往只需要關注運算元量的最高次項,其它次要項和常數項可以忽略
在沒有特殊說明時,我們所分析的演算法的時間複雜度都是指最壞時間複雜度
給幾個例子:
資料結構與演算法 時間複雜度與空間複雜度
解決乙個問題的方法可能有很多,但能稱得上演算法的,首先它必須能徹底解決這個問題 稱為準確性 且根據其編寫出的程式在任何情況下都不能崩潰 稱為健壯性 程式和演算法是完全不同的概念。演算法是解決某個問題的想法 思路 而程式是在根據演算法編寫出來的真正可以執行的 例如,要依次輸出一維陣列中的資料元素的值,...
大O符號與時間複雜度
大o符號 big o notation 是用於描述函式漸進行為的數學符號。也可以這麼說 用乙個大o,在其括號 中,用另乙個函式來描述原來的函式的數量級的漸進上界 電腦科學中,用於分析演算法複雜性非常有用 這個符號有兩種形式上很接近但迥然不同的使用方法 無窮大漸近與無窮小漸近。然而這個區別只是在運用中...
演算法與資料結構 時間複雜度
複雜度是衡量乙個演算法效率高低的乙個重要的因素,一般分為時間複雜度和空間複雜度。空間複雜度,一般在排序等 抽象資料型別的運算和物理實現 有關。本篇主要介紹時間複雜度的一些概念。我們在ram模型 1 記憶體無限大 2 基本運算o 1 下面考慮接下來的內容。準確的說,演算法的複雜性是執行演算法所需要的計...