前言: 學習這東西,很枯燥也很煩,參考許多博文,選了許多。結合一些東西,記錄一下, 也是爲了之後回顧學習。算法
算法效率: 編程
說到算法效率 , 不得不提兩個指標,那就是函數
時間複雜度 學習
空間複雜度測試
好的算法應該具有時間效率高和存儲量低的特色。spa
計算機能快速完成大量複雜的數據處理,可是要完成這個工做,計算機也是須要必定的資源的。得根據數據大小和算法來消使用處理器資源。要想程序可以高效的運行,就要考慮到算法的效率問題了。算法效率的評估, 怎麼評估呢,那就是這兩個指標了。設計
時間複雜度:評估執行程序所需的時間。能夠估算出程序對處理器的使用程度。code
空間複雜度:評估執行程序所需的存儲空間。能夠估算出程序對計算機內存的使用程度。blog
咱們在設計算法的時候。通常是先考慮系統環境,在考慮時間複雜度和空間複雜度, 中間取一個合適的點,一般時間複雜度要比空間複雜度更容易產生問題,因此咱們大多主要研究時間複雜度。內存
時間頻度
一個算法執行所消耗的時間,理論上是不能推論出來的,必須通過機器測試才知道。可是咱們也不可能也沒有必要對每一個算法逐個進行上機測試,只須要知道算法花費的時間就能夠了。算法花費的時間與算法中語句的執行次數成正比例,哪一個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱爲語句頻度或時間頻度。記爲T(n)。
時間複雜度
時間頻度T(n) 。 n 爲問題的規模,當n不斷的變化時,時間頻度T(n) 也會隨之不斷的變化。有時候咱們想知道它的變化呈現出什麼規律,因此 有了時間複雜度的概念。
算法中 基本操做重複執行的次數,是問題規模 n 的某個函數 用 T(n) 表示。 若是有某個輔助函數 f (n), 當n趨近於無窮大的時候,T(n) / f(n) 的極限值爲不等於0 的常數。則 f (n) 爲T(n) 的同數量級函數,表示爲 T(n)=O(f(n)) 它稱爲算法的漸進時間複雜度,簡稱時間複雜度。
大O表示法
上面用O( ) 來表示算法時間複雜度的記法,稱之爲大O 表示法。
評估一個算法咱們能夠從三個角度來評估: 分別爲最理想狀況,最壞狀況,和平均狀況。 從測試結果來看, 平均狀況大多和最壞結果持平,並且評估最壞狀況也能夠避免後面出現的糟糕狀況。因此通常狀況下,咱們設計算法時都要直接估算最壞狀況的複雜度。
大O表示法O(f(n)中的f(n)的值能夠爲一、n、logn、n²等,所以咱們能夠將O(1)、O(n)、O(logn)、O(n²)分別能夠稱爲常數階、線性階、對數階和平方階,那麼如何推導出f(n)的值呢?咱們接着來看推導大O階的方法。
推導大O階
推導大O階,咱們能夠按照以下的規則來進行推導,獲得的結果就是大O表示法:
1.用常數1來取代運行時間中全部加法常數。
2.修改後的運行次數函數中,只保留最高階項
3.若是最高階項存在且不是1,則去除與這個項相乘的常數。
常數階:
int m= 0 ;n = 100 //執行一次 m = (1+n)*n/2 ; //執行一次 system.out.prntln(m)// 執行一次
上面算法的運行次數的函數爲 f(n) = 3,根據推導大O階的規則1,咱們常數3改成1,則這個算法的時間複雜度爲O(1)。若是 m = (1+n)*n/2這條語句再執行10遍,由於這與問題大小n的值並無關係,因此這個算法的時間複雜度仍舊是O(1),咱們能夠稱之爲常數階。
線性階:
線性階主要分析循環結構的運行狀況。
for(int i=0;i<n;i++){ //時間複雜度爲O(1)的算法 ... }
循環體中的代碼執行了n次,所以時間複雜度爲O(n)。
對數階 :
int number=1; while(number<n){ number=number*2; //時間複雜度爲O(1)的算法 ... }
number每次乘以2後,都會愈來愈接近n,當number不小於n時就會退出循環。假設循環的次數爲X,則由2^x=n得出x=log₂n,所以得出這個算法的時間複雜度爲O(logn)。
平方階:
下面是循環嵌套
for(int i=0;i<n;i++){ for(int j=0;j<n;i++){ //複雜度爲O(1)的算法 ... }
內層循環的時間複雜度在講到線性階時就已經得知是O(n),如今通過外層循環n次,那麼這段算法的時間複雜度則爲O(n²)。
其餘常見覆雜度
除了常數階、線性階、平方階、對數階,還有以下時間複雜度:
f(n)=nlogn時,時間複雜度爲O(nlogn),能夠稱爲nlogn階。
f(n)=n³時,時間複雜度爲O(n³),能夠稱爲立方階。
f(n)=2ⁿ時,時間複雜度爲O(2ⁿ),能夠稱爲指數階。
f(n)=n!時,時間複雜度爲O(n!),能夠稱爲階乘階。
f(n)=(√n時,時間複雜度爲O(√n),能夠稱爲平方根階。
算法中常見的f(n)值根據幾種典型的數量級複雜度比較
O(n)、O(logn)、O(√n )、O(nlogn )隨着n的增長,複雜度提高不大,所以這些複雜度屬於效率高的算法,反觀O(2ⁿ)和O(n!)當n增長到50時,複雜度就突破十位數了,這種效率極差的複雜度最好不要出如今程序中,所以在動手編程時要評估所寫算法的最壞狀況的複雜度。
更直觀的圖:
T(n)
0 5 10 15 20 25 n
T(n)值隨着n的值的變化而變化,其中能夠看出O(n!)和O(2ⁿ)隨着n值的增大,它們的T(n)值上升幅度很是大,而O(logn)、O(n)、O(nlogn)隨着n值的增大,T(n)值上升幅度則很小。
經常使用的時間複雜度按照耗費的時間從小到大依次是:
O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n³)<O(2ⁿ)<O(n!)