紮實打牢資料結構演算法根基,從此不怕演算法面試系列之007 week01 02-07 簡單的複雜度分析

皿哥的技術人生發表於2023-04-18

1、複雜度分析

複雜度分析本身是非常理論化的一個內容,在電腦科學中,有一個專門的學科叫做——計算複雜性理論

很多童鞋看過《演算法導論》,這本書的內容很多很強調演算法導論。

但是實際上,對於普通程式設計師來說,不需要過度強調理論化的內容。因為工作中更多面對的是實際的
軟體工程,工程化的工作不需要面對太多理論性的東東。

2、複雜度分析

複雜度分析的作用:是為了表示演算法的效能。

對於同樣一個任務,可能有多個實現方式,即多個演算法。這些不同的演算法,它們的時間效能是否有差異呢?


我們雖然可以用一個測試用例,或者一組測試用例實際比較效能差異。
但是,這樣的比較結果有侷限性。


比如,需要保證執行不同演算法的計算機硬體裝置的效能一致,甚至深入的說,他們的OS當時的狀態都需要是一致的。
這本身很難保證,而且測試結果也與我們的測試用例設計和用例輸入相關。


而且,最重要的是這樣比較是事後的

如何突破侷限性,如何事前比較呢?
種種這樣的需求,都需要我們有一套工具,從數學的層面,用抽象的方式,判斷一個演算法的效能是怎樣的?

為了回應這樣的需求,就產生了複雜度分析這樣一個概念。

3、複雜度分析和演算法效能的關係

複雜度分析,如何表示演算法的效能呢?

需要注意的是,演算法複雜度分析通常考慮最壞的情況。


這樣的思想非常普遍,比如上班時,為了不遲到,考慮最長需要多少時間,甚至將堵車的時間都考慮進去。

即,複雜度分析,表示的是演算法執行的上界。


mark

對於我們的線性查詢法程式碼,我們來進行一個複雜度分析吧,程式碼再一次貼出來:

public static <E> int search(E [] data,E target){
    for (int i = 0; i < data.length; i++)
        if (data[i].equals(target))
            return i;
    return -1;
}

mark

具體的分析過程如下:
n = data.length
T 表示時間
T和n的關係到底是怎樣的?
T = n?n個元素全部掃描了一遍? 就是n?
T = 2n?if裡有比較、有返回結果這2步 就是2n?
T = 3n? 其實if中的data[i],要在陣列data中找到i這個元素,是一步定址,也需要算作一個子步驟。 3n了?
T = 4n?for迴圈中也包含每次要做的事情,i<data.length,也是一個判斷操作,所以4n?

T = 5n?for迴圈中還有一個i++的操作,所以5n?
T = 5n+2? int i =0;加1次,return -1;加1次,所T=5n+2?
……


其實,再繼續分析下去還可以分析出很多可能,就不繼續分析了,為什麼不繼續了呢?


因為真的分析的話,拿出for迴圈對應的彙編程式碼,看看這個迴圈執行了多少指令?


可是拿出彙編程式碼也不夠,因為彙編程式碼對應著機器指令,而機器指令不僅僅是程式碼有多少行而已,
還要追溯到執行程式碼的CPU架構上,有些複雜指令在有些CPU上,就一個指令,但在另外一些CPU上,可能就是多個指令。


對於上層應用軟體開發者來說,分析清楚每一行高階語言程式碼對應著多少機器指令,是一件非常困難,甚至說不可能的事情,其實也沒有必要。

而且即便T=5n+2,那這個等式的時間單位是多少呢?是毫秒ms嘛?肯定不對應時間,對應的是指令數,但是一條指令在cpu中執行多久我們知道嘛?

我們不知道。


所以,這些其實我們都不需要考慮,我們需要進行一個化簡。這也是電腦科學家們定義複雜度分析這個概念時做過的事兒,沒錯,他們做了化簡。


我們不需要知道執行這樣一個迴圈,對這n個元素操作,每一次迴圈需要執行多少個指令;
我們只需要知道,整個演算法和這個data陣列的大小,和這個資料規模n成一個正比的關係即可。


4、O(n)

這個就記作O(n),表示的就是執行時間和資料規模n之間的一個正比關係。
進一步看,如果:
T = c1*n + c2
這個演算法我們就可以記作O(n),即常數c1、c2都被我們忽略掉了,即演算法複雜度的世界中,常數不重要。

5、複雜度描述的是什麼?

複雜度描述的是:隨著資料規模的增大,演算法效能的變化趨勢。

mark

假設有2個演算法,分別是T1和T2,它們的詳細情況如下:

T1 = 10000n
T2 = 2n²
第一個演算法 O(n)級別的演算法,第二個演算法O(n²)級別的演算法。
從複雜度理論的角度來看,第一個演算法優於第二個演算法。

**因為總是會存在某一臨界點n0,當n>n0,T1<T2。
可以計算出,這裡的臨界點n0為5000。
一旦資料規模大於5000,演算法一的效能優勢就體現出來了,而且n越大,體現的越明顯。

所以O(n)描述的就是隨著n的變化,演算法的效能的變化趨勢,

而不是說n取某個值時,演算法的效能。


實際上,如果測試資料小於5000,比如為100時,第二個演算法O(n²)反而優於第一個演算法O(n);


但是評價演算法效能,我們要看n逐漸上漲的情況,甚至看n無窮大的情況

相關文章