算法的時間復雜度與空間復雜度

概述

執行效率是考量一個算法是否高效的主要指標。然而時間、空間復雜度又是衡量算法執行效率的主要維度

一、事后統計法的局限

以前通過統計、監控實際代碼的運行就能夠獲取算法執行的時間和占用的內存大小。這種事后統計方法雖然能夠評估算法的執行效率,但還是存在諸多缺陷。

  1. 測試結果非常依賴測試環境

    測試環境中硬件配置的不同對測試結果會產生很大的影響。

  2. 測試結果受數據規模的影響較大

    對于同一個算法而言,測試數據量的大小不同,其所得出的性能測試結果也會不同。

二、大 O復雜度表示法

如下一段代碼:

public int sum(int n){
     1   int sum = 0;
     2   for(int i = 0; i<n ; i++){
     3       sum = sum +1;
        }
        return sum;
    }

假設每一段代碼的執行時間單位為T,那么第1行代碼執行時間為T,第3行代碼由于執行了n次,那么執行時間為nT所以這段代碼的總執行時間為(n+1)T,由此可知:所有代碼的執行時間T(n)與每行代碼的執行次數n成正比。

接下來再看一段代碼

public int sum(int n){
     1   int sum = 0;
     2   for (int i = 0 ; i<= n ; ++i){
     3       for (int j = 0 ; j<= n ; ++j){
     4           sum = sum + i*j;
            }
        }
        return sum;
    }

這里每行代碼的執行時間單位仍舊為T,那么第1行代碼的執行時間為T,第4行代碼由于執行了n2次,所以執行時間為n2T。因此,整段代碼的執行時間為:(n2+1)T 。

將以上規律總結成一個公式,就是我們所知的大O表達式

T(n) = O ( f (n) )

其中:T(n)代表代碼所執行的時間;n表示數據規模的大小;f(n)表示每行代碼執行的次數總和。而公式中的O則表明了代碼的執行時間T(n)與 f(n) 表達式成正比。

大O復雜度分析表示法,并不具體表示代碼真正的執行時間,而是表示代碼執行時間隨數據規模增長的變化趨勢,一般叫作漸進時間復雜度(asymptotic time complexity),簡稱時間復雜度。同時,當n趨于無限大的時候,我們就可以忽略公式中的低階、常量、與系數三部分。只需記錄一個最大的量級,如 T(n) = O(2n2 + 2n +3) 我們省略掉其中的低階、常量、與系數所得出的最終結果為:T(n) = O(n2)。因此以上兩段代碼的時間復雜度就可以記為 : T(n) = O(n) ;T(n) = O(n2)。

三、時間復雜度分析

  1. 只關注循環執行次數最多的一段代碼:

    關于這一點,之前的代碼示列就是很好的說明,這里不再贅述。

  2. 加法法則:總復雜度等于量級最大的那段代碼的復雜度

    比如如下一段代碼:

    public int sum(int n){
            
            int sumOne = 0;
            for (int i = 0; i <= 1000 ; ++i){
       1         sumOne += i;
            }
    
            int sumTwo = 0;
            for (int i= 0; i< n ; ++i){
        2        sumTwo += i;
            }
    
            int sumThree = 0;
            for (int i = 0; i< n ; ++i){
                for (int j = 0 ; j < n ;++j){
        3            sumThree = sumThree + i *j;
                }
            }
    
            return sumOne + sumTwo + sumThree;
        }
    

    這段代碼共分為三個部分,分別求sumOne、sumTwo、sumThree。我們可以分別解析每一個部分的時間復雜度,然后再從他們之中選取一個量級最大的作為整段代碼的復雜度。

第一段代碼執行了1000次,所以其代表的是一個常量級的執行時間,跟n的規模無關,可以將其忽略掉。

第二段代碼和第三段代碼分別執行了 n 次和 n2次,所以他們的時間復雜度分別為O(n) 和O(n2)。

綜合這三段代碼的時間復雜度,我們取其中最大的量級,那么整段代碼的復雜度就為:O(n2)

因此將上述這個公式抽象一下就可以得出:

如果: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)))

  1. 乘法法則:嵌套代碼的復雜度等于嵌套內外代碼復雜度的乘積

    如果T1(n) = O(f(n)),T2(n) = O(g(n));那么 T(n) = T1(n) x T2(n) = O(f(n)) x O(g(n) = O(f(n) x g(n))

public int sum(int n){

        int result = 0;

        for (int i = 0 ; i < n ;++i){
   1         result = result + subSum(n);
        }

        return result;
    }

    public int subSum(int n){
        int subSum = 0;

        for (int j = 0 ; j < n ; ++j){
    2        subSum += j;
        }

        return subSum;
    }

其中:第一段,第二段代碼都是執行了n次,時間復雜度都是 T(n) = O(n)。但由于第二段代碼是嵌套在第一段代碼之中執行的,因此整個代碼的時間復雜度應為:T(n) = T1(n) x T2(n) = O(n) x O(n) = O(n2)

四、常見時間復雜度

?

多項式量級 非多項式量級
常量階O(1) 指數階O(2n)
對數階O(logn) 階乘階O(n!)
線性階O(n)
線性對數階O(nlogn)
平方階O(n2)、立方階O(n3)、··· 、k次方階O(nk)
  1. 常量階 O(1)

    一般來說,只要算法中不存在循環語句、遞歸語句、即使有成千上萬行代碼,其時間復雜度仍舊是O(1)

  1. 對數階O(logn),線性對數階O(nlogn)

    int i = 1;
    while( i <= n){
        i = i * 2;
    }
    

    如上一段代碼中,i 的取值為 20, 21, 22,···· , 2x-1, 2x 成等比隊列。要想知道這段代碼執行了多少次,求出 2x = n 的結果就行。 x = log2n,所以這段代碼的時間復雜度就是 O( log2n),這里忽視掉底數,那么所有的對數階時間復雜度可以表示為O(logn)。

  2. O(m+n)、O(m * n)

     public int sum(int m , int n){
    
            int sumOne = 0;
    
            for (int i = 0 ; i<= m ; ++i){
                sumOne += m;
            }
    
            int sumTwo = 0;
    
            for (int j = 0 ; j<= n ; ++j){
                sumTwo += j;
            }
    
            return sumOne+sumTwo;
        }
    

    上述代碼中,復雜度取決于兩個數據規模 m 與 n,因此無法事先評估m 與 n 誰的量級更大,因此加法法則在這里不適用。因此上段代碼的時間復雜度即為O(m+n)。但是乘法法則依舊適用:T1(m) x T2(n) = O(f(m) x f(n))。

五、空間復雜度分析

空間復雜度就是漸進空間復雜度(asymptotic space complexity),表示算法的存儲空間與數據規模之間的增長關系。

 public void initArray(int n){
     1   int[] arr = new int[n];
        for (int i = 0 ; i<= n ; ++i){
            arr[i] = i * i;
        }
    }

如上述代碼所示,我們在第一行代碼中申請了一個大小為n的int類型數組,除此之外其他的代碼都沒有占據更多的空間,因此整段代碼的空間復雜度就是O(n),相對于時間復雜度而言,空間復雜度的分析要更為簡單。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容