1. 程式人生 > 實用技巧 >【資料結構】時間複雜度和空間複雜度計算

【資料結構】時間複雜度和空間複雜度計算

時間複雜度AND空間複雜度專項

本文參考:https://www.cnblogs.com/coder-programming/p/11093608.html

時間維度:是指執行當前演算法所消耗的時間,我們通常用「時間複雜度」來描述。
空間維度:是指執行當前演算法需要佔用多少記憶體空間,我們通常用「空間複雜度」來描述。

時間複雜度

一個演算法花費的時間與演算法中語句的執行次數成正比例,哪個演算法中語句執行次數多,它花費時間就多。 一個演算法中的語句執行次數稱為語句頻度或時間頻度。記為 T(n)。

常見的演算法時間複雜度由小到大依次為:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<Ο(nk)<Ο(2n) ,隨著問題規模 n 的不斷增大,上述時間複雜度不斷增大,演算法的執行效率越低

常見的時間複雜度:

常見的時間複雜度:

常數階 O(1)

對數階 O(log2n)

線性階 O(n)

線性對數階 O(nlog2n)

平方階 O(n^2)

立方階 O(n^3)

k 次方階 O(n^k)

指數階 O(2^n)

常見階數串講

  • 常數階 O(1)

    • 沒有迴圈結構,程式碼上萬行都可以,消耗並不伴隨某個的增長而增長,都是O(1)
  • 對數階O(log2n)

    • 舉個例子
    int n=1000;
    
    int i=1;
    
    while(i<=n){
        i=i*2;
    }
    
    cout<<"啦啦啦啦i="<<i<<endl;
    

    看在while迴圈中執行了多少次:while終止條件是i>n的時候,即當2的x次方等於n時結束迴圈,那麼顯然x=log2n。也就是說while迴圈執行了log2n次後就結束了,那麼這個演算法的時間複雜度就是log2n。

    從這個例子可以看出,如果將迴圈改成

    i=i*3;
    

    那麼複雜度自然就變成了log3n。

  • 線性階O(n)

    現在你已經基本入門啦,我們直接上例子,線性階很好理解,就是在迴圈中變數增長從倍數變成了單個增長。

    int n=1000;
    
    int i=1;
    
    while(i<=n){
        i++;
    }
    
    cout<<"啦啦啦啦i="<<i<<endl;
    

    顯然i需要增加n次才可以執行結束,故時間複雜度為O(n)

  • 線性對數階O(nlogN)

    套娃!外層迴圈執行n次,內部迴圈需要執行logN次,那麼一共就是n*logN啦,故時間複雜度為O(nlogN)。

    繼續上程式碼:

    int j=0;
    
    for(int i=1;i<=n;i++){
        j=1;
        while(j<n){
            j=j*2;//時間複雜度為O(log2n)
        }
    }
    

    這個時間複雜度就是O(nlog2n)

  • 平方階O(n²)

    平方階和線性對數階類似,也是套娃!

    外層n,內層n不就成n²了嗎!

    如果外層m,內層n,那麼就是O(mn)

  • 立方階O(n³)、K次方階O(n^k)

    類似~

運演算法則

以上舉例都是套娃或者單個迴圈的,如果遇到多個怎麼辦?這就涉及到時間複雜度計演算法則了:

只關注迴圈執行次數最多的一段程式碼

加法法則:總複雜度等於量級最大的那段程式碼的複雜度
如果 T1(n)=O(f(n)),T2(n)=O(g(n));那麼 T(n)=T1(n)+T2(n)=max(O(f(n)), O(g(n))) =O(max(f(n), g(n))).

乘法法則:巢狀程式碼的複雜度等於巢狀內外程式碼複雜度的乘積
T(n) = T1(n) * T2(n) = O(n*n) = O(n2)

平均時間複雜度和最壞時間複雜度

  • 平均時間複雜度:所有可能輸入例項均以等概率出現的情況下,該演算法的執行時間。
  • 最壞時間複雜度:最壞情況下(即演算法執行時間最長的情況)
  • 平均時間複雜度與最壞時間複雜度是否一致,與演算法有關。

空間複雜度

類似於時間複雜度,一個演算法的空間複雜度定義為該演算法所耗費的儲存空間,也是問題規模n的函式

(別問,上面一句話我沒看懂。。。)

可以理解為,空間複雜度是用來評判一個演算法的執行所需佔用的臨時儲存空間。在做演算法分析的時候,主要討論的是時間複雜度。從使用者體驗上看,更看重程式的執行速度,所以有時候為了提升演算法速度使用空間來換時間。

突然想到那種變態排序,1~2015範圍,直接開闢2016的陣列大小,有數的就標記為1其餘為0,然後遍歷輸出。。。時間複雜度:O(n)

定義

演算法的空間複雜度的計算公式記作:S(n)=O(f(n)),其中,n為問題的規模,f(n)為語句關於n所佔儲存空間的函式。

舉個例子:

void print(int n) {
  int i = 0;//常量階,不算問題規模
  int[] a = new int[n];//規模為n
  for (i; i <n; ++i) {
    a[i] = i * i;
  }

  for (i = n-1; i >= 0; --i) {
    print out a[i]
  }
}

顯然程式碼開闢了一個規模為n的陣列,故整體的空間複雜度為O(n)