經常可以在一些書上看到這樣的公式:程序=數據結構+算法所以算法 的重要性是不言而喻的.
那么什么是算法呢?
算法的基本特性有:
1.確定性-----算法中的每一條指令無二義性.
2.有窮性-----算法經過有限的計算次數后結束.
3.可行性-----算法是由一些基本可行的運算實現.
4.算法有0個或者多個輸入.
5.算法有1個或者多個輸出.
那么我們又依據什么規則來設計一種特定的算法呢?
1.首先設計的算法要是正確的.根據嚴蔚敏數據結構一書中介紹了算法的這種正確性的四個層次.
層次一:程序不含語法錯誤.這是最基本的,也是在初學者最容易出現錯誤的地方
層次二:程序對於幾組輸入能夠得到符合規格的結果.
層次三:程序對於精心挑選,條件苛責的輸入仍然能得到符合規格的結果.這是大多數程序能夠達到的層次.
層次四:程序對於任何輸入都能得到符合規格的結果.這樣的程序可以稱得上完美,但是要實現這樣的程序絕非易事.
在實際工作中,層次一往往是通過編譯工具進行檢查修正,否則存在語法錯誤的程序是無法運行的.而后幾個層次
往往是使用專門的測試工具進行測試.
2.其次程序是可讀的,算法不僅是面向機器,更重要的是面向讀者.如果實現算法的程序是晦澀難懂的,那么這樣的算法
肯定稱不上好的算法.
3.還要程序是健壯的.所謂健壯是指實現算法的程序,不僅對於正確的輸入能夠給出正確的結果.對於不合要求的輸入
仍然能夠進行錯誤判別.識別出究竟是哪類錯誤.
4.最后就是算法時間效率和空間效率.所謂時間效率是指算法執行的時間.當然越快越好.空間效率是指算法執行所占
用的內存空間.當然是越小越好.
而對於算法最重要的就是效率了,那么效率如何度量呢
一種方式是將不同算法用程序實現,然后比較運行時間.這是一種最直觀的比較算法效率的方法.很明顯這種方式要求
我們將要比較的算法首先一一實現之后再來進行比較.不難看出這種比較方式是比較笨拙的.而且不同的硬件條件下
運行的時間也肯定是有差異的.
二種方式是不需要事先將算法實現來計算算法的時間效率:
這種方式需要考慮如下幾個方面的因素:
1.問題的規模.比如計算100的階乘肯定和計算1000的階乘肯定運行時間不同.100和1000就是規模
2.書寫算法的程序語言越高低,時間效率越低.反之,效率越高.
3.代碼本身的質量,是否有冗余代碼等等
4.計算機指令執行的快慢.
我們撇開語言,代碼質量,硬件質量快慢這些認為可控因素不談.
同一算法的時間效率主要取決於問題規模的大小.
對於同一問題的不同算法,在相同的問題規模下:
我們以100的累加為例.
計算100的階乘,可以是1+2+3+4+5......100
也可以是(1+100)+(2+99)+(3+98)+......+(50+51)即簡化為101*50;
很顯然第二種計算方法要便於計算,時間效率高於第一種.
接下來我們將上例用代碼進行描述:
第一種方式的累加
1 int sum=0; ① 2 for(int i=1;i<=100;i++) ② 3 sum=sum+i; ③
第二種方式的累加
1 int sum=0; ① 2 for(int i=1,j=101;i<=50&&j>=51;j--,i++)② 3 sum=sum+i+j;③
我們將算法的時間效率用算法中基本指令執行的次數來描述.不區別不同基本指令執行時間的差異.
第一種方式的累加:
①中int sum=0;執行的1次
②中 int i=0執行1次;i<=100;i++分別執行了100次
③中sum=sum+i執行了100次
所以總共的次數為 1+1+2*100+100=302;
第二種方式的累加:
①中int sun=0執行了1次
②中int i=0執行了1次,i<=50&&j>=51;j--,i++分別執行了50次
③中sum=sum+i+j執行了50次
所以總共的次數為 1+1+2*50+50=152;
很顯然假設每條指令執行的時間相同那么方式二的累加是不是比方式一的累加省了很多時間呢.
這里我們引入時間頻度T(n)的概念.T(n)為實現一種算法的指令執行的次數(n為問題規模).
那么兩種方式分別為:T1(n)=2*n+n+2=3n+2
T2(n)=2*(n/2)+n/2+2=3n/2+2
我們用漸進時間復雜度來對時間頻道進行描述,簡稱時間復雜度.
漸進時間復雜度即存在f(n)使得當n-->無限大 有lim(T(n)/f(n))=C(常數).
那么O(f(n))即為該算法的時間復雜度.T(n)=O(f(n));
很明顯T1(n),T2(n)時間復雜度均為O(n);
那么具體如何計算時間復雜度呢?
比如N*N矩陣相乘:
代碼如下:
1 int i,j,k; ① 2 for(i=1;i<=n;i++) ② 3 for(j=1;j<=n;j++) ③ 4 { 5 c[i][j]=0; ④ 6 for(k=1;k<=n;k++) ⑤ 7 c[i][j]+=a[i][k]*b[k][j];⑥ 8 }
其中
①中語句執行1次
②中i=1執行一次,剩下的均執行n次
③中j=1執行n次;剩下的均執行n^2次
④中語句執行n^2次
⑤中k=1執行n^2次,剩下的均執行n^3次
⑥中語句執行n^3次
所以T(n)=1+1+2*n+n+2*n^2+n^2+n^2+2*n^3=2+3n+4n^2+3n^3
很顯然當f(n)=cn^3時候 lim(T(n/f(n)))=常數 故時間復雜度為O(n^3);
但是O(n^3)的復雜度是好還是不好呢.
根據經驗-判斷:
一般情況下可根據此規則判斷一個算法的復雜度的優劣:
c < log2n < n < n*log2n < n2 < n3 < 2n < 3n < n! (c是一個常量)
|--------------------------|--------------------------|-------------|
較好 一般 較差
其中c是一個常量,如果一個算法的復雜度為c 、 log2n 、n 、 n*log2n,那么這個算法時間效率比較高
如果是 2n , 3n ,n!,那么稍微大一些的n就會令這個算法不能動了,居於中間的幾個則差強人意。
最后補充一些知識:
1計算規則
若T1(n)=O(f1(n)),T2(m)=O(f2(m));
加法規則:則T(m,n)=T(m)+T(n)=O(max(f1(n),f2(m)))
乘法規則: 則T(m,n)=T(m)*T(n)=O(f1(n)*f2(m))
常數可去掉: 則T1(m)=O(f(m)) T2(m)=O(c*f(m)) T(m)=T1(m)=T2(m)=O(f(m))
2.關於最壞復雜度
某些情況下同一算法的時間復雜度不僅和輸入規模有關還與輸入順序有關.這種情況下我們計算其最壞
情況下的時間復雜度來度量算法的時間效率.
from:http://www.cnblogs.com/vpoet/p/4659724.html