1. 程式人生 > >數據結構子時間復雜度

數據結構子時間復雜度

大小 占用內存 表示 a+b 一個 推導 一次 有關 穩定

算法之時間復雜度

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

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

時間復雜度:評估執行程序所需的時間。可以估算出程序對處理器的使用程度。

空間復雜度:評估執行程序所需的存儲空間。可以估算出程序對計算機內存的使用程度。

時間復雜度

時間頻度

一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。並且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度。記為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表示法O(f(n)中的f(n)的值可以為1、n、logn、n2等,因此我們可以將O(1)、O(n)、O(logn)、O(n2)分別可以稱為常數階、線性階、對數階和平方階,那麽如何推導出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(n2)。

常見算法的時間復雜度

冒泡排序(交換排序)

最好:O(N)

平均:O(N^2)

最壞:O(N^2)

特點:1、冒泡排序是一種用時間換空間的排序方法,n小時好 。2、最壞情況是把順序的排列變成逆序,或者把逆序的數列變成順序,最差時間復雜度O(N^2)只是表示其操作次數的數量級 3、最好的情況是數據本來就有序,復雜度為O(n)

快速排序(交換排序)

最好:O(N*log2N)

平均:O(N*log2N)

最壞:O(N^2)

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

直接選擇(選擇排序)

最好:O(N)

平均:O(N^2)

最壞:O(N^2)

數據結構子時間復雜度