算法複雜度計算學習

尊重原創,源博主地址

前面學習過好多次,都是得過且過一直沒有學會(lll¬ω¬),這次下定決心(ง •_•)ง

算法的效率

算法的效率主要有以下兩個複雜度開評估:

時間複雜度:評估執行程序所需要的時間,可以估算出程序對處理器的使用程度
空間複雜度:評估程序執行所需要的存儲空間,可以估算出對計算機內存的實用程度

設計程序算法的時候,考慮系統環境,然後權衡時間複雜度和空間複雜度,選取一個平衡點。不過時間複雜度要比空間複雜度更容易產生問題,並且現在的計算機硬件的內存一半是充足的,所以研究的主要是時間複雜度,不特別說明的情況下,複雜度就是指時間複雜度。

時間複雜度

時間頻度
一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。並且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲T(n)。
時間複雜度
前面提到的時間頻度T(n)中,n稱爲問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現什麼規律,爲此我們引入時間複雜度的概念。一般情況下,算法中基本操作重複執行的次數是問題規模n的某個函數,用T(n)表示,若有某個輔助函數f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值爲不等於零的常數,則稱f(n)是T(n)的同數量級函數,記作T(n)=O(f(n)),它稱爲算法的漸進時間複雜度,簡稱時間複雜度。

大O表示法

像前面用O( )來體現算法時間複雜度的記法,我們稱之爲大O表示法。
算法複雜度可以從最理想情況、平均情況和最壞情況三個角度來評估,由於平均情況大多和最壞情況持平,而且評估最壞情況也可以避免後顧之憂,因此一般情況下,我們設計算法時都要直接估算最壞情況的複雜度。
大O表示法O(f(n)中的f(n)的值可以爲1、n、logn、n²等,因此我們可以將O(1)、O(n)、O(logn)、O(n²)分別可以稱爲常數階、線性階、對數階和平方階,那麼如何推導出f(n)的值呢?我們接着來看推導大O階的方法。

  • 推導大O階段

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

  • 常數階
int sum = 0,n = 100; //執行一次  
sum = (1+n)*n/2; //執行一次  
System.out.println (sum); //執行一次 

上面算法的運行的次數的函數爲f(n)=3,根據推導大O階的規則1,我們需要將常數3改爲1,則這個算法的時間複雜度爲O(1)。如果sum = (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²)。

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

n+(n-1)+(n-2)+….+1
= n^2/2+n/2
根據此前講過的推導大O階的規則的第二條:只保留最高階,因此保留n²/2。根據第三條去掉和這個項的常數,則去掉1/2,最終這段代碼的時間複雜度爲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),可以稱爲平方根階。

複雜度的比較

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章