演算法複雜度簡述
零、前言
在我本科參與ACM院隊培訓時,來自校隊的學長就給我們講過複雜度的概念,可惜當時年輕不懂事,沒有好好消化,現在來補補課。
一、時間複雜度
1.1 時間頻度
一個演算法花費的時間與演算法中語句的執行次數成正比。演算法中語句的執行次數稱為語句頻度或時間頻度。記為T(n)。
這個概念瞭解即可,抄自百科,不是重點。
1.2 時間複雜度
在T(n)中,n稱為問題的規模,n不同,T(n)自然也不同。一般情況下,演算法中基本操作重複執行的次數是問題規模n的某個函式。這裡的n可以理解為某個入引數組的長度,或者某個矩陣的元素個數。
設定一個T(n)的同數量級函式f(n),當n趨近於無窮大時,T(n)/f(n)的極限為一個常數。記T(n) = O(f(n))
補充:其實複雜度的符號現在我們基本只能看到大寫字母O,在《演算法導論》中Big-O整個family都有介紹,包括O,Θ,Ω。本來都是希臘字母,大家為了打起來方便都用了英文字母O,打起來方便對程式設計師來說真的是很重要的一點,再加上不是數學系的人不見得對數學符號有很深的執念,差不多得了。這幾個符號之間的差距解釋起來還蠻繁瑣的,當前我也沒把握說清楚,就先跳過吧。見諒見諒
用O(n)來體現演算法時間複雜度的記法被稱作大O表示法。
1.3 時間複雜度計算方法
一般我們評估一個演算法都是直接評估它的最壞情況下的複雜度。
大O表示法O(f(n))中的f(n)的值可以為1、n、logn、n^2 等,所以我們將O(1)、O(n)、O(logn)、O( n^2 )分別稱為常數階、線性階、對數階和平方階。
常見的時間複雜度由小到大依次為:Ο(1)<Ο(logn)<Ο(n)<Ο(nlogn)<Ο(n^2)<Ο(n^3)<…<Ο(2^n)<Ο(n!)
所以,我們應該儘可能地選用多項式階O(n^k)複雜度的演算法,指數階和階乘階使我們不希望看到的,因為開銷實在太大。
1.3.1大O表示法三規則
- 用常數1取代執行時間中的所有加法常數
- 只保留最高階項
- 去除最高階的常數
1.3.2具體步驟
1.找出演算法中的基本語句;
演算法中執行次數最多的那條語句就是基本語句,通常是最內層迴圈的迴圈體。
2.計算基本語句的執行次數的數量級;
只需計算基本語句執行次數的數量級,這就意味著只要保證基本語句執行次數的函式中的最高次冪正確即可,可以忽略所有低次冪和最高次冪的係數。
3.用大Ο記號表示演算法的時間效能。
將基本語句執行次數的數量級放入大Ο記號中。如果演算法中包含巢狀的迴圈,則基本語句通常是最內層的迴圈體,如果演算法中包含並列的迴圈,則將並列迴圈的時間複雜度相加。
1.4時間複雜度計算小結
- 對於一些簡單的輸入輸出語句或賦值語句,認為需要O(1)時間;
- 對於順序結構,需要依次執行一系列語句所用的時間可採用大O下”求和法則”;
- 對於選擇結構,如if語句,它的主要時間耗費是在執行then字句或else字句所用的時間,需注意的是檢驗條件也需要O(1)時間;
- 對於迴圈結構,迴圈語句的執行時間主要體現在多次迭代中執行迴圈體以及檢驗迴圈條件的時間耗費,一般可用大O下”乘法法則”;
- 對於複雜的演算法,可以將它分成幾個容易估算的部分,然後利用求和法則和乘法法則計算整個演算法的時間複雜度。
求和法則:是指若演算法的2個部分時間複雜度分別為 T1(n)=O(f(n))和 T2(n)=O(g(n)),則 T1(n)+T2(n)=O(max(f(n), g(n))),用於順序結構;
乘法法則:是指若演算法的2個部分時間複雜度分別為 T1(n)=O(f(n))和 T2(n)=O(g(n)),則 T1*T2=O(f(n)*g(n)),用於迴圈巢狀結構。
1.5時間複雜度總結
一般來說,只要演算法中不存在迴圈語句,其時間複雜度就是Ο(1)。其中Ο(logn)、Ο(n)、 Ο(nlogn)、Ο(n2)和Ο(n3)稱為多項式時間,而Ο(2n)和Ο(n!)稱為指數時間。電腦科學家普遍認為前者(即多項式時間複雜度的演算法)是有效演算法,把這類問題稱為P(Polynomial,多項式)類問題,而把後者(即指數時間複雜度的演算法)稱為NP(Non-Deterministic Polynomial,,非確定多項式)問題。
二、空間複雜度
類似於時間複雜度的討論,一個演算法的空間複雜度(Space Complexity)S(n)定義為該演算法所耗費的儲存空間,它也是問題規模n的函式。漸近空間複雜度也常常簡稱為空間複雜度。
空間複雜度是對一個演算法在執行過程中臨時佔用儲存空間大小的度量。一個演算法在計算機儲存器上所佔用的儲存空間,包括儲存演算法本身所佔用的儲存空間,演算法的輸入輸出資料所佔用的儲存空間和演算法在執行過程中臨時佔用的儲存空間這三個方面。
三、後話
一般我們在聊複雜度的時候,都預設是時間複雜度。這兩個複雜度是往往是相互影響的。更小的時間複雜度可能會佔用更多空間;反之,追求更少的空間複雜度,可能會佔用更長的執行時間。很多時候我們都用空間來換取時間,可能原因是現在的儲存裝置相對於計算機的算力更便宜吧。另一方面,時效性也是很多程式需要考慮更重要的問題。