複雜度分析的套路及常見的複雜度

彤哥讀原始碼發表於2020-07-25

file

前言

本篇文章收錄於專輯:http://dwz.win/HjK,點選解鎖更多資料結構與演算法的知識。

你好,我是彤哥,一個每天爬二十六層樓還不忘讀原始碼的硬核男人。

上一節,我們一起學習了表示複雜度的幾個符號,我們說,通常使用大O來表示演算法的複雜度,不僅合理,而且書寫方便。

那麼,使用大O表示法評估演算法的複雜度有沒有什麼套路呢?以及常見的複雜度有哪些呢?

本節,我們就來解決這兩個問題。

前情回顧

在正式講解套路之前,我們先回憶一下前面幾節講到的內容。

在第2節,我們學習了漸近分析法,將演算法的複雜度與輸入規模掛鉤,隨著輸入規模的增大,演算法執行的時間將呈現一種什麼樣的趨勢,將這個趨勢用函式表示,再去除低階項和常數項,就得到了演算法的時間複雜度。

在第3節,我們分別從最壞、平均、最好三種情況來分析了演算法的複雜度,得出結論,一般使用最壞情況來評估演算法的複雜度。

在第4節,我們通過動態陣列的插入元素及經典快速排序的時間複雜度,解釋了有的時候不能使用最壞情況來評估演算法的複雜度。

在第5節,我們從讀音、數學、通俗理解三個方面分析了各種表示演算法複雜度的符號,得出結論還是使用大O比較香,大O代表了演算法的上界,它與前面講到的最壞情況往往是對應的。

所以,這裡所說的套路也是針對大部分情況,也就是最壞情況,對於一些個例,比如經典快排,我們雖然也是使用大O表示他們的複雜度,但是,其實是一種均攤的複雜度。

好了,讓我們看看計算演算法複雜度的套路到底是什麼吧。

套路

我將計算演算法複雜度的套路歸納為以下五步:

  1. 明確輸入規模n;
  2. 考慮最壞情況或均攤情況,如果最壞情況為個例,那就是均攤;
  3. 計算演算法執行的次數與n的關係,並用函式表示出來;
  4. 去除低階項;
  5. 去除常數項;

比如,對於在陣列中查詢指定元素的操作:

  1. 輸入規模為陣列的長度n;
  2. 考慮最壞情況為目標元素不在陣列中;
  3. 演算法的執行次數為遍歷所有陣列元素,也就是n次,用函式表示f(n) = n;
  4. 去除低階項,沒有低階項,還是n;
  5. 去除常數項,沒有常數項,還是n;

所以,在陣列中查詢指定元素的時間複雜度為O(n)。

OK,使用這種方式可以很快的計算出演算法的複雜度,也不需要進行額外的計算,非常快捷高效。

常見的複雜度

上面我們說了,複雜度的計算就是計算與輸入規模n的關係,所以,我們想想數學中關於n的函式就能得出常見的複雜度了,我繪製了一張表格:

與n的關係 英文釋義 複雜度 示例
常數(不相關) Constant O(1) 陣列按索引查詢元素
對數相關 Logarithmic O(logn) 二分查詢
線性相關 Linear O(n) 遍歷陣列的元素
超線性相關 Superlinear O(nlogn) 歸併排序、堆排序
多項式相關 Polynomial O(n^c) 氣泡排序、插入排序、選擇排序
指數相關 Exponential O(c^n) 漢諾塔
階乘相關 Factorial O(n!) 行列式展開
n的n次方 O(n^n) 不知道有沒有這種演算法

在這張表中,複雜度是依次增加的,可以看到常數複雜度O(1)無疑是最好的,讓我們用一張圖來直觀感受下:

file

後記

本節,我們一起學習了複雜度分析的套路以及常見的複雜度,到目前為止,我們不管是舉例還是講解基本上都在說時間複雜度。

那麼,空間複雜度又是什麼呢?空間與時間之間如何權衡呢?

下一節,我們接著聊。

關注公號主“彤哥讀原始碼”,解鎖更多原始碼、基礎、架構知識。

相關文章