目錄
1:為什麼需要複雜度分析?
2:大o複雜度表示法
3:時間複雜度
3.1 只關注迴圈執行次數最多的一段**
3.2 總的複雜度等於量級最大的那段**的複雜度(加法法則)
3.3 巢狀**的複雜度等於巢狀內外**複雜度的乘積(乘法法則)
3.4 時間複雜度
4:空間複雜度
5:時間複雜度擴充套件
網上一直有乙個非常火的話題:什麼樣的開發者才能算是乙個優秀的開發者。乙個優秀的開發者:首先完成業務功能是基本,然後寫的**足夠優雅(可讀性要好,在這裡多說一句,你寫的**不僅僅是給機器看的,也是給人看的),最後效率一定要高。
那麼問題來了。我們如何衡量**的效率是否足夠高呢?這裡就需要提到重點了:時間,空間複雜度分析。
時間和空間複雜度分析是資料結構與演算法的核心所在。
平常工作中,寫好某一功能後,本地**跑一遍,通過分析就能夠得到**執行的時間和占用的記憶體空間。那麼為什麼我們還需要進行複雜度分析呢?難道複雜度分析出來的資料比實際跑一次更準確。no,絕對不是。
說一下前者有什麼侷限之處。
測試的結果非常依賴環境。同樣的**,i9處理器肯定比i3處理器要執行的快得多。如果遷移到另外的機器上,i9處理器換成了i5處理器,它的執行效率可能遠遠比不上i9了。
測試結果受資料規模的影響很大。執行乙個排序演算法,如果本身需要排序的資料就已經排好序了,那麼執行的時間就很快。如果測試的資料規模太小,測試結果就無法反映演算法的效能。
所以,我們需要一種可以不用具體的測試資料測試就可以粗略估算演算法執行效率的方法。
通常情況下,相同條件,演算法執行的時間越短效率越高。我們如何在不允許**的情況下,用」肉眼「得到一段**的執行時間呢?
下面有一段**,我們來分析一下:
我們假設每行**的執行時間都一樣,為unit_time(單位時間),第7行和第8行只會執行一次,也就是1個unit_time;第9行和第10行會執行n次,所以需要2n*unit_time。對於上述**總的執行時間就是(2n + 2)*unit_time。
因為執行的次數不可能為負,所以**執行時間t(n)與每行**的執行次數成正比。
按照上面的學習思路,看下面的這段**:
每行**的執行時間依舊是unit_time,第8,9,10行執行的次數是1次,第11,12行執行了n遍,需要2n*unit_time,第13,14行是迴圈巢狀,需要執行2n2 *unit_time ,所以t(n) = (2n2 + 2n +3) * unit_time。
小結:所有**的執行時間t(n)與每行**的執行次數n成正比
公式:t(n) = o(f(n))
t(n)表示**的執行時間,n表示資料規模,f(n)表示每行**執行次數的總和。o表示**的執行時間t(n)與f(n)表示式成正比。
所以,第一段**t(n) = o(2n + 2),第二段**t(n) = o(2n2 + 2n + 3)
重點:大o時間複雜度實際上並不具體表示**真正的執行時間,而是表示**執行時間隨著資料規模增長的變化趨勢,所以,也叫做漸進時間複雜度。使用大0表示法可以忽略公式中的低階,常量,係數。剛剛講的示例公式可以記為:t(n) = o(n),t(n) = o(n2)
進行時間複雜度分析的有效方法?
分析乙個演算法,一段**,只關注迴圈執行次數最多的那一段就可以了。
以上述第一段**為例,第7行和第8行只會執行一次,第9行和第10行會執行n次,所以時間複雜度就是o(n)。
如果說一段**中有多個迴圈,那麼最終的時間複雜度就取量級最大的那個。
如下**:
按照上訴所學,單獨看cal方法,時間複雜度是t(n) = o(n),但是迴圈中的f()函式本身不是乙個常量行為。f方法的時間複雜度也是t(n) = o(n)。所以,整個cal的時間複雜度就是t(n) = o(n2)
複雜度量級如下:
常量階 o(1)
對數階 o(logn)
線性階 o(n)
線性對數階 o(nlogn)
平方階 o(n2) 立方階o(n3) ....k次方階o(nk)
指數階o(2n)
階乘階 o(n!)
空間複雜度相對於時間複雜度要簡單的多。
空間複雜度就是漸進空間複雜度,表示演算法的儲存空間與資料規模之間的增長關係。
常見的空間複雜度:o(1) o(n) o(n2)o(logn) o(nlogn)
舉個例子
和時間複雜度一樣,常量級的忽略。第9行申請了乙個大小為n的記憶體位址,除此之外,剩下的**沒有占用更多的空間。所以整段**的空間複雜度就是o(n)。第10,11行執行的時間複雜度是(2n)*unit_time。不要把時間複雜度和空間複雜度混淆。
某些情況下,上面的時間複雜度分析方法還不能很好的解決問題。下面還有一些不太常用的關於時間複雜度的一些擴充套件。
最好情況時間複雜度
最壞情況時間複雜度
平均情況時間複雜度
均攤時間複雜度
最好最壞情況時間複雜度
上述**實現的功能是在array陣列中查詢值為x的下標。如果上述**中沒有加上break,按照前面所學,它的時間複雜度應該是t(n) = o(n)。但是加上break後,它的時間複雜度還是o(n)嗎?顯然可能不是了。如果查詢的陣列中第乙個值便匹配成功了,立即跳出迴圈,時間複雜度就是o(1); 如果最後乙個值才匹配成功,那麼它的時間複雜度就是o(n)。
所以:最好情況時間複雜度就是,在最理想的情況下,執行這段**的時間複雜度。最壞情況時間複雜度就是,在最糟糕的情況下,執行這段**的時間複雜度。
資料結構系列之複雜度分析
1 時間複雜度 求解演算法的時間複雜度的具體步驟是 找出演算法中的基本語句 演算法中執行次數最多的那條語句就是基本語句,通常是最內層迴圈的迴圈體。計算基本語句的執行次數的數量級 只需計算基本語句執行次數的數量級,這就意味著只要保證基本語句執行次數的函式中的最高次冪正確即可,可以忽略所有低次冪和最高次...
資料結構之複雜度分析(二)
一.什麼是複雜度分析 二.為什麼需要複雜度分析 三.如何進行複雜度分析 空間複雜度 四.複雜度分析的細化 衡量一段 的執行效率最主要的無非是 快 省 其中快是指執行速度快,省是指占用空間少。這裡所指的複雜度分析指的是時間 空間複雜度。我們常說的以空間換取時間也正是對應這兩點。時間複雜度 執行時間隨著...
演算法分析之複雜度
時間複雜度 是度量演算法執行的時間長短或者說是程式執行的次數。詳細說明 乙個演算法,處理n條資料需要的時間可以用表示式 a n b來表示的話,稱它的時間複雜度為o n 也就是說,100條資料需要1秒的話,1000條資料需要10s。如果是用表示式 a n n b n c的話,複雜度為o n的平方 這樣...