什麼是算法和數據結構?若是將最終寫好運行的程序比做戰場,咱們程序員即是指揮做戰的將軍,而咱們所寫的代碼即是士兵和武器。程序員
那麼數據結構和算法是什麼?答曰:兵法!故,數據結構和算法是一名程序開發人員的必備基本功,不是一朝一夕就能練成絕世高手的。冰凍三尺非一日之寒,須要咱們平時不斷的主動去學習積累。算法
先來看一道題:若是 a+b+c=1000,且 a*a+b*b=c*c(a,b,c 爲天然數),如何求出全部a、b、c可能的組合?數組
普通解法:瀏覽器
import time # 用於記錄計算開始的時間 start_time = time.time() for a in range(0,1001): for b in range(0,1001): for c in range(0,1001): if a*a+b*b == c*c and a+b+c == 1000: print("a=%d,b=%d,c=%d"%(a,b,c)) # 用於記錄計算結束的時間 end_time = time.time() print("本次運算用時總計%f秒"%(end_time-start_time))
運行結果爲:數據結構
a=0,b=500,c=500 a=200,b=375,c=425 a=375,b=200,c=425 a=500,b=0,c=500 本次運算用時總計397.615515秒
請注意運行時間是397.615515秒那麼,若是本題稍微改一下,改成先來看一道題:若是 a+b+c=2000,且 a*a+b*b=c*c(a,b,c 爲天然數),如何求出全部a、b、c可能的組合?這個時候他們解題思路和a+b+c=1000是同樣的,無非就是將1000改成2000,而這種解決問題的思路就叫作算法,只不過算法也有好壞而已。數據結構和算法
算法是計算機處理信息的本質,由於計算機程序本質上是一個算法來告訴計算機確切的步驟來執行一個指定的任務。通常地,當算法在處理信息時,會從輸入設備或數據的存儲地址讀取數據,把結果寫入輸出設備或某個存儲地址供之後再調用。算法是獨立存在的一種解決問題的方法和思想。對於算法而言,實現的語言並不重要,重要的是思想。算法能夠有不一樣的語言描述實現版本(如C描述、C++描述、Python描述等)函數
仍是針對上面的例子:若是 a+b+c=1000,且 a*a+b*b=c*c(a,b,c 爲天然數),如何求出全部a、b、c可能的組合?優化解法:性能
import time # 用於記錄計算開始的時間 start_time = time.time() # 注意這裏是兩重循環 for a in range(0,1001): for b in range(0,1001-a): c=1000-a-b if a*a+b*b == c*c: print("a=%d,b=%d,c=%d"%(a,b,c)) # 用於記錄計算結束的時間 end_time = time.time() print("本次運算用時總計:%f秒"%(end_time-start_time))
運行結果爲:學習
a=0,b=500,c=500 a=200,b=375,c=425 a=375,b=200,c=425 a=500,b=0,c=500 本次運算用時總計316.337260秒
一、執行時間反應算法效率優化
對於同一問題,咱們給出了兩種解決算法,在兩種算法的實現中,咱們對程序執行的時間進行了測算,發現兩段程序執行的時間相差懸殊(397.615515秒相比於316.337260秒),由此咱們能夠得出結論:實現算法程序的執行時間能夠反應出算法的效率,即算法的優劣。
二、單靠時間絕對可信嗎?
假設咱們將第二次嘗試的算法程序運行在一臺配置古老性能低下的計算機中,狀況會如何?極可能運行的時間並不會比在咱們的電腦中運行算法一的397.615515秒快多少。單純依靠運行的時間來比較算法的優劣並不必定是客觀準確的!程序的運行離不開計算機環境(包括硬件和操做系統),這些客觀緣由會影響程序運行的速度並反應在程序的執行時間上。那麼如何才能客觀的評判一個算法的優劣呢?
三、時間複雜度與「大O記法」
咱們假定計算機執行算法每個基本操做的時間是固定的一個時間單位,那麼有多少個基本操做就表明會花費多少時間單位。固然對於不一樣的機器環境而言,確切的單位時間是不一樣的,可是對於算法進行多少個基本操做(即花費多少時間單位)在規模數量級上倒是相同的,由此能夠忽略機器環境的影響而客觀的反應算法的時間效率。
對於算法的時間效率,咱們能夠用「大O記法」來表示。
「大O記法」:對於單調的整數函數f(),若是存在一個整數函數g()和實常數c>0,使得對於充分大的n總有f(n)<=c*g(n),就說函數g是f的一個漸近函數(忽略常數),記爲f(n)=O(g(n))。也就是說,在趨向無窮的極限意義下,函數f的增加速度受到函數g的約束,亦即函數f與函數g的特徵類似。
時間複雜度:假設存在函數g(),使得算法A處理規模爲n的問題示例所用時間爲T(n)=O(g(n)),則稱O(g(n))爲算法A的漸近時間複雜度,簡稱時間複雜度,記爲T(n)
四、時間複雜度的基本計算規則
for a in range(0,1001): for b in range(0,1001): for c in range(0,1001): if a*a+b*b == c*c and a+b+c == 1000: print("a=%d,b=%d,c=%d"%(a,b,c))
時間複雜度:T(n) = O(n*n*n) = O(n^3)
優化後:
for a in range(0,1001): for b in range(0,1001-a): c=1000-a-b if a*a+b*b == c*c: print("a=%d,b=%d,c=%d"%(a,b,c))
時間複雜度:T(n) = O(n*n) = O(n^2), 因而可知,咱們嘗試的第二種算法要比第一種算法的時間複雜度好多的。
注意:常常將log2n(以2爲底的對數)簡寫成logn
所消耗的時間從小到大:O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(n^n)