【進階之路】算法的時間複雜度與空間複雜度

你們好,我是練習java兩年半時間的南橘,從一名連java有幾種數據結構都不懂超級小白,到如今懂了一點點的進階小白,學到了很多的東西。知識越分享越值錢,我這段時間總結(包括從別的大佬那邊學習,引用)了一些日常學習和工做中的重點(自我認爲),但願給你們帶來一些幫助java

在這裏插入圖片描述
由於最近在學習軟件設計師、正巧趕上了概念性的算法題。由於以前學習並不系統的緣由,雖然能作題,可是卻不是很是瞭解算法中時間複雜度。本着研究學習的心理,這幾天就開始研究算法中的時間複雜度,還真學到了一些東西。程序員

1、時間複雜度

在計算機科學中,時間複雜性,又稱時間複雜度,算法的時間複雜度是一個函數,它定性描述該算法的運行時間。這是一個表明算法輸入值的字符串的長度的函數。時間複雜度經常使用大O符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱爲是漸近的,亦即考察輸入值大小趨近無窮時的狀況。算法

  • 一、時間頻度 一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。可是咱們沒有要對每一個算法都上機測試。有經驗的程序員只需看一看就能知道哪一個算法花費的時間多,哪一個算法花費的時間少就能夠了。而且一個算法花費的時間與算法中語句的執行次數成正比例,哪一個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲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(f(n)) 爲算法的漸進時間複雜度,簡稱時間複雜度。

Landau符號(大O符號)實際上是由德國數論學家保羅·巴赫曼(Paul Bachmann)在其1892年的著做《解析數論》首先引入,由另外一位德國數論學家艾德蒙·朗道(Edmund Landau)推廣。Landau符號的做用在於用簡單的函數來描述複雜函數行爲,給出一個上或下(確)界。在計算算法複雜度時通常只用到大O符號,Landau符號體系中的小o符號、Θ符號等等比較不經常使用。這裏的O,最初是用大寫希臘字母,但如今都用大寫英語字母O;小o符號也是用小寫英語字母o,Θ符號則維持大寫希臘字母Θ。數組

因此,在其餘條件不變的狀況下,選擇時間複雜度低的算法更有利於提升程序的效率。你們不要以爲算法這東西沒有用,以爲是頂尖的程序員才用獲得。其實咱們在工做中,要常常根據狀況新增許多工具類,這些解決具體問題的工具類每每又要涉及到遞歸、循環、排序、動態規劃等問題。對於咱們來講,可以實現功能就夠了,可是若是能進一步地下降這些工具類的時間複雜度,或許能讓咱們感受到本身的價值吧。數據結構

2、時間複雜度

常見的時間複雜度有:常數階O(1),對數階O(log2n),線性階O(n), 線性對數階O(nlog2n),平方階O(n²), k次方階O(n^k),指數階O(2^n)。隨着問題規模n的不斷增大,上述時間複雜度不斷增大,算法的執行效率越低。
從大佬那邊拿到圖片函數

一、常數階O(1)

int a = 1;
int b = 2;
int c = 3;

咱們假定每執行一行代碼所須要消耗的時間爲1個時間單位,那麼以上3行代碼就消耗了3個時間單位。O(1)的1表明的是常數,常數階的算法的複雜度是不會隨着問題規模的增大而增大,這樣的代碼無論有多少行,均可以用O(1)來表示它的時間複雜度。工具

二、對數階O(logN)

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

從數學上咱們能夠很簡單的看出它的函數:性能

2^f(n)<=n,因此f(n)<=log2n學習

每次循環的時候 i都會乘2,那麼總共循環的次數就是log2n,所以這個代碼的時間複雜度爲O(log2n)。可是,底數如何對於程序運行的效率來講並不重要,就和以前的常數階同樣,常數部分則忽略,一樣的,若是不一樣時間複雜度的倍數關係爲常數,那也能夠近似認爲二者爲同一量級的時間複雜度。測試

若是這樣很差理解,咱們能夠用二叉樹來表示。若是二叉樹的是以紅黑樹等平衡二叉樹實現的,則n個節點的二叉排序樹的高度爲 log2n+1 ,其查找效率爲O(Log2n),近似於折半查找。

三、線性階O(n)

for(i = 0; i <n; i++) {
   int a =1;
   int b=1;
   int c =a+b;
}

這段代碼會執行多少次呢?若是從代碼上來看,每一行都會執行n次(或者n-1次),因此最後會執行 T(n)=n+3(n-1)=4n-3次。
咱們知道:大O符號表示法並非用於來真實表明算法的執行時間的,它是用來表示代碼執行時間的增加變化趨勢的。因此線性階O(n)的時間複雜度實際上是O(n);

四、線性對數階O(nlogN)

for(m = 1; m < n; m++) {
    i = 1;
    while(i < n) {
        i = i * 2;
    }
}

線性對數階O(nlogN) 就很是很是容易理解了,將時間複雜度爲O(logn)的代碼循環N遍的話,那麼它的時間複雜度就是 n*O(logN)。

五、平方階O(n²)

for(i = 1; i <= n; i++){
   for(j = 1; j <= n; j++) {
       j = i;
       j++;
    }
}

把 O(n) 的代碼再嵌套循環一遍,它的時間複雜度就是 O(n²) 了。

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

參考上面的O(n²) 去理解就行了,O(n³)至關於三層n循環,O(n^k)就是k層循環。

3、空間複雜度

一個程序的空間複雜度是指運行完一個程序所需內存的大小。與時間複雜度相相似的,利用程序的空間複雜度,能夠對程序的運行所須要的內存多少有個預先估計一個程序執行時除了須要存儲空間和存儲自己所使用的指令、常數、變量和輸入數據外,還須要一些對數據進行操做的工做單元和存儲一些爲現實計算所需信息的輔助空間。程序執行時所需存儲空間包括如下兩部分。

-1 、固定部分:這部分空間的大小與輸入/輸出的數據的個數多少、數值無關,主要包括指令空間(即代碼空間)、數據空間(常量、簡單變量)等所佔的空間,這部分屬於靜態空間。

-2 、可變空間:這部分空間的主要包括動態分配的空間,以及遞歸棧所需的空間等,這部分的空間大小與算法有關。一個算法所需的存儲空間用f(n)表示。S(n)=O(f(n)),其中n爲問題的規模,S(n)表示空間複雜度。

一、空間複雜度 O(1)

int i = 1;
int j = 1;
int k = i + j;

若是算法執行所須要的臨時空間不隨着某個變量n的大小而變化,即此算法空間複雜度爲一個常量,可表示爲 O(1)。
i、j、k所分配的空間都不隨着處理數據量變化,所以它的空間複雜度 S(n) = O(1)。

二、空間複雜度 O(n)

int[] m = new int[n]
for(i = 0; i <n; i++) {
   int a =1;
   int b=1;
   int c =a+b;
}

這段代碼的第一行new了一個數組出來,這個數據佔用的大小爲n,後面雖然有循環,但沒有再分配新的空間,所以,這段代碼的空間複雜度主要看第一行便可,即 S(n) = O(n),同時時間複雜度也是O(n)。

間複雜度取決於額外建立的數組m,若是使用二維數組 new int[n][m] ,則空間複雜度是 O(n*m)

4、複雜度的選擇

對於相同的輸入規模,數據分佈不相同也影響了算法執行路徑的不一樣,所以所須要的執行時間也不一樣。根據不一樣的輸入,將算法的時間複雜度分析分爲3種狀況。
  • 一、最佳狀況。使算法執行時間最少的輸入。通常狀況下,不進行算法在最佳狀況下的時間複雜度分析。如已經證實基於比較的排序算法的時間複雜度下限爲O(nlog2n),那麼就不須要白費力氣去千方百計將該類算法改進爲線性時間複雜度的算法。

  • 二、最壞狀況。使算法執行時間最多的輸入。通常會進行算法在最壞時間複雜度的分析,由於最壞狀況是在任何輸入下運行時間的一個上限,它給咱們提供一個保障,實際狀況不會比這更糟糕。另外,對於某些算法來講,最壞狀況仍是至關頻繁的。並且對於許多算法來講,平均狀況一般與最壞狀況下的時間複雜度同樣。

  • 三、平均狀況。算法的平均運行時間,通常來講,這種狀況很難分析。舉個簡單的例子,現要排序10個不一樣的整數,輸入就有10!種不一樣的狀況,平均狀況的時間複雜度要考慮每一種輸入及其該輸入的機率。平均狀況分析能夠按如下3個步驟進行:

    • 1 將全部的輸入按其執行時間分類
    • 2 肯定每類輸入發生的機率
    • 3 肯定每類輸入發生的機率

算法很重要的一點就是時間換空間或者空間換時間

當追求一個較好的時間複雜度時,可能會使空間複雜度的性能變差,便可能致使佔用較多的存儲空間。

反之,求一個較好的空間複雜度時,可能會使時間複雜度的性能變差,便可能致使佔用較長的運行時間。

另外,算法的全部性能之間都存在着或多或少的相互影響。所以,當設計一個算法(特別是大型算法)時,要綜合考慮算法的各項性能,算法的使用頻率,算法處理的數據量的大小,算法描述語言的特性,算法運行的機器系統環境等各方面因素,纔可以設計出比較好的算法。

相關文章
相關標籤/搜索