數據結構01 算法的時間複雜度和空間複雜度

一、算法的概念:

算法 (Algorithm),是對特定問題求解步驟的一種描述。html

解決一個問題每每有不止一種方法,算法也是如此。那麼解決特定問題的多個算法之間如何衡量它們的優劣呢?有以下的指標:算法

二、衡量算法的指標:

(1)時間複雜度:執行這個算法須要消耗多少時間。函數

(2)空間複雜度:這個算法須要佔用多少內存空間。性能

  同一個問題能夠用不一樣的算法解決,而一個算法的優劣將影響到算法乃至程序的效率。算法分析的目的在於爲特定的問題選擇合適算法。一個算法的評價主要從時間複雜度和空間複雜度來考慮測試

  算法在時間的高效性和空間的高效性之間一般是矛盾的。因此通常只會取一個平衡點。一般咱們假設程序運行在足夠大的內存空間中,因此研究更多的是算法的時間複雜度。spa

 

三、算法的時間複雜度

  (1)語句頻度T(n): 一個算法執行所花費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但咱們不可能對每一個算法都上機測試,只需知道哪一個算法花費的時間多,哪一個算法花費的時間少就能夠了。 並且一個算法花費的時間與算法中的基本操做語句的執行次數成正比例,哪一個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度,記爲T(n)。
 
  (2)時間複雜度: 在剛纔提到的語句頻度中,n稱爲問題的規模,當n不斷變化時,語句頻度T(n)也會不斷變化。但有時咱們想知道它的變化呈現什麼規律。爲此,咱們引入時間複雜度概念。 通常狀況下,算法中的基本操做語句的重複執行次數是問題規模n的某個函數,用T(n)表示,如有某個輔助函數f(n),使得當n趨近於無窮大時,T(n) / f(n) 的極限值爲不等於零的常數,則稱f(n)是T(n)的同數量級函數。記做 T(n)=O( f(n) ),稱O( f(n) )  爲算法的漸進時間複雜度,簡稱時間複雜度。
  T(n) 不一樣,但時間複雜度可能相同。 如:T(n)=n²+5n+6 與 T(n)=3n²+3n+2 它們的T(n) 不一樣,但時間複雜度相同,都爲O(n²)。
 
  (3)常見的時間複雜度有:常數階O(1),對數階O(log 2n),線性階O(n),線性對數階O(nlog 2n),平方階O(n 2),立方階O(n 3), k次方階O(n k),指數階O(2 n)。隨着問題規模n的不斷增大,上述時間複雜度不斷增大,算法的執行效率越低。

 

  (4)平均時間複雜度和最壞時間複雜度:code

    平均時間複雜度是指全部可能的輸入實例均以等機率出現的狀況下,該算法的運行時間。htm

    最壞狀況下的時間複雜度稱最壞時間複雜度。通常討論的時間複雜度均是最壞狀況下的時間複雜度。 這樣作的緣由是:最壞狀況下的時間複雜度是算法在任何輸入實例上運行時間的界限,這就保證了算法的運行時間不會比最壞狀況更長。blog

    

  (5)如何求時間複雜度:  遞歸

  【1】若是算法的執行時間不隨着問題規模n的增長而增加,即便算法中有上千條語句,其執行時間也不過是一個較大的常數。此類算法的時間複雜度是O(1)。
    public static void main(String[] args) {
        int x = 91;
        int y = 100;
        while (y > 0) {
            if (x > 100) {
                x = x - 10;
                y--;
            } else {
                x++;
            }
        }
    }
該算法的時間複雜度爲:O(1) 
這個程序看起來有點嚇人,總共循環運行了1100次,可是咱們看到n沒有?
沒。這段程序的運行是和n無關的,
就算它再循環一萬年,咱們也無論他,只是一個常數階的函數
 
  【2】當有若干個循環語句時,算法的時間複雜度是由嵌套層數最多的循環語句中最內層語句的頻度f(n)決定的。
1         int x = 1;
2         for (int i = 1; i <= n; i++) {
3             for (int j = 1; j <= i; j++) {
4                 for (int k = 1; k <= j; k++) {
5                     x++;
6                 }
7             }
8         }
該算法的時間複雜度爲:O(n 3)  
該程序段中頻度最大的語句是第5行的語句,內循環的執行次數雖然與問題規模n沒有直接關係,可是卻與外層循環的變量取值有關,而最外層循環的次數直接與n有關,所以該程序段的時間複雜度爲 O(n 3)  
 
  【3】算法的時間複雜度不只僅依賴於問題的規模,還與輸入實例的初始狀態有關。
  在數值 A[n-1,n-2 ...0] 中查找給定值k的算法大體以下:   
1         int i = n - 1;
2         while (i >= 0 && (A[i] != k)) {
3             i--;
4         }
5         return i;
該算法的時間複雜度爲:O(n)    
此算法中第3行語句的頻度不只與問題規模n有關,還與輸入實例A中的各元素取值和k的取值有關:若是A中沒有與k相等的元素,那麼第3行語句的頻度爲 f(n)=n ,該程序段的時間複雜度爲 O(n)  
 
 
  (6)用時間複雜度來評價算法的性能 
    用兩個算法A 1和A 2求解同一問題,時間複雜度分別是O(100n 2),O(5n 3)
    (1) 5n 3/100n 2=n/20 ,當輸入量n<20時,100n > 5n 3 ,這時A 2花費的時間較少。
    (2)隨着問題規模n的增大,兩個算法的時間開銷之比 5n 3/100n 2=n/20 也隨着增大。即當問題規模較大時,算法A 1比算法A 2要高效的多。 它們的漸近時間複雜度O(n2)和O(n3) 評價了這兩個算法在時間方面的性能。在算法分析時,每每對算法的時間複雜度和漸近時間複雜度不予區分,而常常是將漸近時間複雜度 O(f(n)) 簡稱爲時間複雜度,其中的f(n)通常是算法中頻度最大的語句頻度。

 

四、算法的空間複雜度  

   空間複雜度(Space Complexity) 是對一個算法在運行過程當中臨時佔用存儲空間大小的量度,記作 S(n)=O(f(n)) ,其中n爲問題的規模。利用算法的空間複雜度,能夠對算法的運行所須要的內存空間有個預先估計。
  一個算法執行時除了須要存儲自己所使用的指令、常數、變量和輸入數據外,還須要一些對數據進行操做的工做單元和存儲一些計算所需的輔助空間。算法執行時所需的存儲空間包括如下兩部分。   
(1)固定部分。這部分空間的大小與輸入/輸出的數據的個數、數值無關。主要包括指令空間(即代碼空間)、數據空間(常量、簡單變量)等所佔的空間。這部分屬於靜態空間。
(2)可變空間,這部分空間的主要包括動態分配的空間,以及遞歸棧所需的空間等。這部分的空間大小與算法有關。
  舉例分析算法的空間複雜度:
    public void reserse(int[] a, int[] b) {
        int n = a.length;
        for (int i = 0; i < n; i++) {
            b[i] = a[n - 1 - i];
        }
    }

上方的代碼中,當程序調用 reserse() 方法時,要分配的內存空間包括:引用a、引用b、局部變量n、局部變量i

所以 f(n)=4 ,4爲常量。因此該算法的空間複雜度 S(n)=O(1)  

 

五、總結

算法的時間複雜度和兩個因素有關:算法中的最大嵌套循環層數;最內層循環結構中循環的次數。

通常來講,具備多項式時間複雜度的算法是能夠接受的;具備指數(不是對數)時間複雜度的算法,只有當n足夠小時纔可使用。通常效率較好的算法要控制在O(log2n) 或者 O(n)

 

歡迎轉載,但請保留文章原始出處

本文地址:http://www.cnblogs.com/nnngu/p/8245787.html

相關文章
相關標籤/搜索