快速掌握算法時間複雜度與空間複雜度

前言

一個算法的優劣好壞,會決定一個程序運行的時間、空間。也許當小數據量的時候,這種影響並不明顯,可是當有巨量數據的時候,算法的好壞帶來的性能差別就會出天差地別。能夠說直接影響了一個產品的高度和廣度。每一個程序員都想用最優的算法解決問題,咱們期待本身寫出的代碼是簡潔、高效的。可是如何評判一個算法的好壞呢?時間複雜度和空間複雜度就是一個很好的標準。html

1. 時間複雜度

1.1 概念

執行算法所須要的計算工做量就是咱們常說的時間複雜度。該值不必定等於接下來要介紹的基本執行次數。是一個大約的數值,具備統計意義。程序員

1.2 基本執行次數T(n)

根據計算,得出的該算法在輸入數據量爲n時的,實際執行次數。該值爲準確的,具體的數值,有數學意義。算法

1.3 時間複雜度

根據基本執行次數,去除係數、常數項等獲得的漸進時間複雜度。用大O表示法。也就是說,隨着數據量的劇增,不一樣常數項和係數,已經大體不可以影響該算法的基本執行次數。常數項和係數對於計算時間複雜度無心義函數

1.4 舉例說明

  1. T(n) = 2: 該函數總共執行兩條語句,因此基本執行次數爲2;時間複雜度爲O(1): 該函數的基本執行次數只有常數項,因此時間複雜度爲O(1)
void test(int n)
{
    int a;
    a = 10;
}
  1. T(n) = 2n: 該函數共循環n次,每次執行2條語句,因此基本執行次數爲2n。時間複雜度捨棄係數,爲O(n)
void test(int n)
{
    int cnt;
    for (cnt = 0; cnt < n; cnt++) {
        int a;
        a= 10;
    }
}
  1. T(n) = 2 * (1 + 2 + 3 + 4 + ... + n) + 1 = 2 * (1 + n) * n / 2 + 1 = n^2 + n + 1。由於共執行(1 + 2 + 3 + 4 + ... + n) 次循環,每次循環執行2條語句,全部循環結束後,最後又執行了1條語句,因此執行次數如上;時間複雜度爲O(n^2),由於n和常數項1忽略,它們在數據量劇增的時候,對於執行次數曲線幾乎沒有影響了
void test(int n)
{
    int cnt1, cnt2;
    for (cnt1 = 0; cnt1 < n; cnt1++) {
        for (cnt2 = cnt1; cnt2 < n; cnt2++) {
            int a;
            a = 10;            
        }
    }
    a = 11;
}
  1. T(n) = 2 * logn 由於每次循環執行2條語句,共執行logn次循環;時間複雜度爲O(logn),忽略掉係數2
void test(int n)
{
    int cnt;
    for (cnt = 1; cnt < n; cnt *= 2) {
        int a;
        a = 10;
    }
}
  1. T(n) = n * logn * 2 由於每次循環2條語句,共執行n * logn次循環;時間複雜度爲O(nlogn),忽略掉係數2
void test(int n)
{
    int cnt1, cnt2;
    for (cnt1 = 0; cnt1 < n; cnt1++) {
        for (cnt2 = 1; cnt2 < n; cnt2 *= 2) {
            int a;
            a = 10;
        }
    }
}
  1. T(n) = 2 * n^3 由於每次循環2條語句,共執行n^3 次循環;時間複雜度爲O(n^3),忽略掉係數2
void test(int n)
{
    int cnt1, cnt2, cnt3;
    for (cnt1 = 0; cnt1 < n; cnt1++) {
        for (cnt2 = 0; cnt2 < n; cnt2++) {
            for (cnt3 = 0; cnt3 < n; cnt3++) {
                int a;
                a = 10;
            }
        }
    }
}
  1. 斐波那契數列的遞歸實現,每次調用該函數都會分解,而後要再調用2次該函數。因此時間複雜度爲O(2^n)
int test(int n)
{
    if (n == 0 || n == 1) {
        return 1;
    }
    return (test(n-1) + test(n-2));
}

1.5 時間複雜度比較

O(1) < O(log2n) < O(n) < O(nlog2n) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)性能

2. 空間複雜度

2.1 概念

一個算法所佔用的存儲空間主要包括:學習

  • 程序自己所佔用的空間
  • 輸入輸出變量所佔用的空間
  • 動態分配的臨時空間,一般指輔助變量

輸入數據所佔空間只取決於問題自己,和算法無關。咱們所說的空間複雜度是對一個算法在運行過程當中臨時佔用存儲空間大小的量度,即第三項。一般來講,只要算法不涉及到動態分配的空間以及遞歸、棧所需的空間,空間複雜度一般爲0(1)。code

2.2 舉例說明

  1. S(n) = O(1).空間複雜度爲O(1),由於只有a, b, c, cnt四個臨時變量。且臨時變量個數和輸入數據規模無關。
int test(int n)
{
    int a, b, c;
    int cnt;
    for (cnt = 0; cnt < n; cnt++) {
        a += cnt;
        b += a;
        c += b;
    }
}
  1. S(n) = O(n).空間複雜度爲O(n),由於每次遞歸都會建立一個新的臨時變量a。且共遞歸n次。
int test(int n)
{
    int a = 1;
    if (n == 0) {
        return 1;
    }
    n -= a;
    return test(n);
}

3. 函數的漸進增加與漸進時間複雜度

在上面的例子中,咱們一般都會捨棄掉係數和常數項。這是由於當輸入量劇增,接近正無窮時,係數和常數項已經不可以影響執行次數曲線。不一樣的係數和常數項曲線會徹底重合。我作了一個折線圖用來比較當輸入值n激增時,n^2 曲線和 2n^2 + 100 曲線。能夠看到,當數據量劇增時,係數和常數項對於統計時間複雜度都再也不有意義,兩條曲線幾乎徹底重合。htm

4. 不一樣算法的時間複雜度 & 空間複雜度

下圖是我作的一個表格,整理了不一樣的排序算法的時間複雜度和空間複雜度供你們參考:blog

感謝你們的閱讀,你們喜歡的請幫忙點下推薦。後面會繼續出精彩的內容,敬請期待!


敬告:排序

本文原創,歡迎你們學習轉載

轉載請在顯著位置註明:

博主ID:CrazyCatJack

原始博文連接地址:http://www.javashuo.com/article/p-ocmfzqon-ez.html


CrazyCatJack
相關文章
相關標籤/搜索