算法與算法分析
目錄
算法+數據結構=程序。 —— Nicklaus Wirth (Pascal之父)
什麼是算法?
學習程序設計時,常聽人說起算法,那麼究竟什麼是算法呢?
算法(Algorithm)是指解題方案的準確而完整的描述,是一系列解決問題的清晰指令,算法代表着用系統的方法描述解決問題的策略機制。也就是說,能夠對一定規範的輸入,在有限時間內獲得所要求的輸出。如果一個算法有缺陷,或不適合於某個問題,執行這個算法將不會解決這個問題。不同的算法可能用不同的時間、空間或效率來完成同樣的任務。一個算法的優劣可以用空間複雜度與時間複雜度來衡量。——摘自《百度百科》
也就是說算法是爲了解決某類問題而規定的一個有限長的操作序列。
算法的特點有哪些?
算法主要有5種重要特點:
-
有窮性
一個算法必須在有限的步驟內結束,且每一步都必須在有窮時間完成。(這句話很好理解,畢竟沒人會期盼去完成一件沒有盡頭的任務。話說死循環好像就不算一個算法呢。) -
確定性
對於每種情況下所應執行的操作,在算法中都有明確規定,不存在二義性。(果然師出數學,脾氣都一樣,一就是一,二就是二,看來算法不適用於宮鬥劇中。) -
可行性
算法中的所有操作都可以通過已經實現的基本操作運算執行有限次來實現。(很明顯,在唐朝造不出火箭,計算機也不能執行超出能力範圍的指令。好的算法要符合實際,可以利用現有的函數,框架等等來實現) -
輸入
一個算法有零個或多個輸出。(沒輸入數據咱可以內置呀!這個程序它不香麼?)#include <iostream> using namespace std; int main() { int n=0; cout<<n<<endl; return 0; }
-
輸出
一個算法有一個或多個輸出。(不能幹活要你作甚!)
算法的評價標準
- 正確性(結果都不對,你莫不是在開玩笑?)
- 可讀性(要想讓別人承認這是個好算法,首先你要讓人家可以看懂。)
- 健壯性(在面對用戶千奇百怪的輸入時,你的程序要抗住不能崩。)
- 高效性(執行時間要儘量短,佔用空間要儘量少。)
算法的時間複雜度
-
問題規模和語句頻度
問題規模是指算法求解問題輸入量的多少,是問題大小的本質。而一條語句的重複執行次數稱爲語句頻度。(一個算法的執行時間大致等於其所有語句執行的時間。) -
時間複雜度的定義
上面我們說道,算法的執行時間隨着問題的規模增長而增長,所以對算法的評價只需看其增長趨勢。在計算機科學中,時間複雜性,又稱時間複雜度,算法的時間複雜度是一個函數,它定性描述該算法的運行時間。這是一個代表算法輸入值的字符串的長度的函數。時間複雜度常用大O符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱爲是漸近的,亦即考察輸入值大小趨近無窮時的情況。——摘自《百度百科》
-
分析方法
(1)只關注循環執行次數最多的一段代碼。
(2)總複雜度等於量級最大的那段代碼的複雜度。
(3)嵌套代碼的複雜度等於嵌套內外代碼複雜度的乘積 -
實例
(1)常量階for(i=0;i<1000;i++) { x++; }
由於算法的執行時間是一個與問題規模n無關的常數,所以算法的時間複雜度爲T(n)=O(1).
(2)線性階
for(i=0;i<n;i++) { x++; }
由於x自增的頻率爲f(n)=n,所以算法的時間複雜度爲T(n)=O(n),稱爲線性階。
(3)平方階
for(i=0;i<n;i++) for(j=0;j<n;j++) x++;
由於x自增頻率爲f(n)=n2,所以算法的時間複雜度爲T(n)=O(n2),稱爲平方階。
(4)立方階
for(i=0;i<n;i++) for(j=0;j<n;j++) for(k=0;k<n;k++) x++;
由於x自增頻率爲f(n)=n3,所以算法的時間複雜度爲T(n)=O(n3),稱爲立方階。
(5)對數階
for(i=0;i<n;i=i*2) { x++; }
由於x自增的頻率爲2f(n)=n,即f(n)=log2n,所以算法的時間複雜度爲T(n)=O(log2n),稱爲對數階。
-
最好、最壞和平均時間複雜度
算法在最好情況下的時間複雜度爲最好時間複雜度(指算法計算量可能達到的最小值);在最壞情況下的時間複雜度爲最壞時間複雜度(指算法計算量可能達到的最大值);算法的平均時間複雜度是指算法在所有可能情況下,按照輸入實例等概率出現時,算法計算量的加權平均值。通常只討論最壞情況下的算法複雜度。
算法的空間複雜度
空間複雜度(Space Complexity)是對一個算法在運行過程中臨時佔用存儲空間大小的量度,記做S(n)=O(f(n))。比如直接插入排序的時間複雜度是O(n^2),空間複雜度是O(1) 。而一般的遞歸算法就要有O(n)的空間複雜度了,因爲每次遞歸都要存儲返回信息。一個算法的優劣主要從算法的執行時間和所需要佔用的存儲空間兩個方面衡量。——摘自《百度百科》
簡而言之,就是計算算法需要佔用的額外輔助空間。
實例
-
常數階
for(i=0;i<n/2;i++) { t=a[i]; a[i]=a[n-i-1]; a[n-i-1]=t; }
該算法只需要額外借用一個變量t,故算法空間複雜度爲O(1)。
-
線性階
for(i=0;i<n;i++) { b[i]=a[n-i-1]; } for(i=0;i<n;i++) { a[i]=b[i]; }
該算法需要額外借用一個大小爲n的輔助數組,故算法空間複雜度爲O(n)。