算法之時間複雜度

 

前言: 學習這東西,很枯燥也很煩,參考許多博文,選了許多。結合一些東西,記錄一下, 也是爲了之後回顧學習。算法

算法效率: 編程

說到算法效率 , 不得不提兩個指標,那就是函數

 時間複雜度 學習

空間複雜度測試

好的算法應該具有時間效率高和存儲量低的特色。spa

計算機能快速完成大量複雜的數據處理,可是要完成這個工做,計算機也是須要必定的資源的。得根據數據大小和算法來消使用處理器資源。要想程序可以高效的運行,就要考慮到算法的效率問題了。算法效率的評估, 怎麼評估呢,那就是這兩個指標了。設計

時間複雜度:評估執行程序所需的時間。能夠估算出程序對處理器的使用程度。code

空間複雜度:評估執行程序所需的存儲空間。能夠估算出程序對計算機內存的使用程度。blog

咱們在設計算法的時候。通常是先考慮系統環境,在考慮時間複雜度和空間複雜度, 中間取一個合適的點,一般時間複雜度要比空間複雜度更容易產生問題,因此咱們大多主要研究時間複雜度。內存

 

時間頻度

一個算法執行所消耗的時間,理論上是不能推論出來的,必須通過機器測試才知道。可是咱們也不可能也沒有必要對每一個算法逐個進行上機測試,只須要知道算法花費的時間就能夠了。算法花費的時間與算法中語句的執行次數成正比例,哪一個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲T(n)。

 

時間複雜度

時間頻度T(n) 。  n 爲問題的規模,當n不斷的變化時,時間頻度T(n) 也會隨之不斷的變化。有時候咱們想知道它的變化呈現出什麼規律,因此 有了時間複雜度的概念。

算法中  基本操做重複執行的次數,是問題規模 n 的某個函數 用 T(n) 表示。 若是有某個輔助函數 f (n),  當n趨近於無窮大的時候,T(n) / f(n) 的極限值爲不等於0 的常數。則 f (n) 爲T(n) 的同數量級函數,表示爲 T(n)=O(f(n))  它稱爲算法的漸進時間複雜度,簡稱時間複雜度。

 

大O表示法

上面用O( ) 來表示算法時間複雜度的記法,稱之爲大O 表示法。

評估一個算法咱們能夠從三個角度來評估: 分別爲最理想狀況,最壞狀況,和平均狀況。 從測試結果來看, 平均狀況大多和最壞結果持平,並且評估最壞狀況也能夠避免後面出現的糟糕狀況。因此通常狀況下,咱們設計算法時都要直接估算最壞狀況的複雜度。

大O表示法O(f(n)中的f(n)的值能夠爲一、n、logn、n²等,所以咱們能夠將O(1)、O(n)、O(logn)、O(n²)分別能夠稱爲常數階、線性階、對數階和平方階,那麼如何推導出f(n)的值呢?咱們接着來看推導大O階的方法。 

推導大O階 
推導大O階,咱們能夠按照以下的規則來進行推導,獲得的結果就是大O表示法: 
1.用常數1來取代運行時間中全部加法常數。 
2.修改後的運行次數函數中,只保留最高階項 
3.若是最高階項存在且不是1,則去除與這個項相乘的常數。

常數階: 

int  m= 0 ;n = 100 //執行一次
m = (1+n)*n/2 ; //執行一次
system.out.prntln(m)// 執行一次

上面算法的運行次數的函數爲 f(n) = 3,根據推導大O階的規則1,咱們常數3改成1,則這個算法的時間複雜度爲O(1)。若是 m = (1+n)*n/2這條語句再執行10遍,由於這與問題大小n的值並無關係,因此這個算法的時間複雜度仍舊是O(1),咱們能夠稱之爲常數階。

線性階:

線性階主要分析循環結構的運行狀況。

for(int i=0;i<n;i++){
//時間複雜度爲O(1)的算法
...
}

循環體中的代碼執行了n次,所以時間複雜度爲O(n)。

對數階 :

int number=1;
while(number<n){
number=number*2;
//時間複雜度爲O(1)的算法
...
}

  number每次乘以2後,都會愈來愈接近n,當number不小於n時就會退出循環。假設循環的次數爲X,則由2^x=n得出x=log₂n,所以得出這個算法的時間複雜度爲O(logn)。

 

平方階:

下面是循環嵌套

 for(int i=0;i<n;i++){   
      for(int j=0;j<n;i++){
         //複雜度爲O(1)的算法
         ... 
      }

內層循環的時間複雜度在講到線性階時就已經得知是O(n),如今通過外層循環n次,那麼這段算法的時間複雜度則爲O(n²)。 

 

其餘常見覆雜度

 

除了常數階、線性階、平方階、對數階,還有以下時間複雜度: 
f(n)=nlogn時,時間複雜度爲O(nlogn),能夠稱爲nlogn階。 
f(n)=n³時,時間複雜度爲O(n³),能夠稱爲立方階。 
f(n)=2ⁿ時,時間複雜度爲O(2ⁿ),能夠稱爲指數階。 
f(n)=n!時,時間複雜度爲O(n!),能夠稱爲階乘階。 
f(n)=(√n時,時間複雜度爲O(√n),能夠稱爲平方根階。

 

算法中常見的f(n)值根據幾種典型的數量級複雜度比較

 

 O(n)、O(logn)、O(√n )、O(nlogn )隨着n的增長,複雜度提高不大,所以這些複雜度屬於效率高的算法,反觀O(2ⁿ)和O(n!)當n增長到50時,複雜度就突破十位數了,這種效率極差的複雜度最好不要出如今程序中,所以在動手編程時要評估所寫算法的最壞狀況的複雜度。

更直觀的圖:

    T(n)

  

        0               5               10             15              20             25            n

 

T(n)值隨着n的值的變化而變化,其中能夠看出O(n!)和O(2ⁿ)隨着n值的增大,它們的T(n)值上升幅度很是大,而O(logn)、O(n)、O(nlogn)隨着n值的增大,T(n)值上升幅度則很小。 
經常使用的時間複雜度按照耗費的時間從小到大依次是:

O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n³)<O(2ⁿ)<O(n!)

相關文章
相關標籤/搜索