數據結構子時間複雜度

算法之時間複雜度

雖然計算機能快速的完成運算處理,但實際上,它也須要根據輸入數據的大小和算法效率來消耗必定的處理器資源。要想編寫出能高效運行的程序,咱們就須要考慮到算法的效率。算法

算法的效率主要由二哥複雜度來評估:函數

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

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

時間複雜度

時間頻度排序

一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但咱們不可能也沒有必要對每一個算法都上機測試,只需知道哪一個算法花費的時間多,哪一個算法花費的時間少就能夠了。而且一個算法花費的時間與算法中語句的執行次數成正比例,哪一個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲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表示法】,它稱爲算法的漸進時間複雜度,簡稱時間複雜度class

大O表示法效率

像前面用O( )來體現算法時間複雜度的記法,咱們稱之爲大O表示法。循環

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

推到大O階

  1. 用常數1來取代運行時間中全部加法常數。

  2. 修改後的運行次數函數中,只保留最高階項 。

  3. 若是最高階項存在且不是1,則去除與這個項相乘的常數。

舉例:

常數階

int a=1 ;//執行一次
int b-1; //執行一次
int c=a+b;//執行一次

上面算法的運行的次數的函數爲f(n)=3,根據推導大O階的規則1,咱們須要將常數3改成1,則這個算法的時間複雜度爲O(1) 。若是int c =a+b這條語句再執行100遍,時間複雜度仍然是O(1), 由於這與問題大小n的值並無關係,咱們能夠稱之爲常數階。

線性階

for(int i=0;i<n;i++)
{
  var a=n; // 1*n次 
}

上面的循環執行了n次,所以時間複雜度爲O(n)。 若是再循環體裏面再加一條 var b=2n, 時間複雜度仍然爲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²)。

常見算法的時間複雜度

冒泡排序(交換排序)

最好:O(N)

平均:O(N^2)

最壞:O(N^2)

特色:一、冒泡排序是一種用時間換空間的排序方法,n小時好 。二、最壞狀況是把順序的排列變成逆序,或者把逆序的數列變成順序,最差時間複雜度O(N^2)只是表示其操做次數的數量級 三、最好的狀況是數據原本就有序,複雜度爲O(n)

快速排序(交換排序)

最好:O(N*log2N)

平均:O(N*log2N)

最壞:O(N^2)

特色:一、n大時好,快速排序比較佔用內存,內存隨n的增大而增大,但倒是效率高不穩定的排序算法。 二、劃分以後一邊是一個,一邊是n-1個, 這種極端狀況的時間複雜度就是O(N^2) 三、最好的狀況是每次都能均勻的劃分序列,O(N*log2N)

直接選擇(選擇排序)

最好:O(N)

平均:O(N^2)

最壞:O(N^2)

相關文章
相關標籤/搜索