1 1、數據結構和算法的做用 2 2、算法引入 3 3、算法的概念 4 4、算法的五大特徵 5 5、執行時間反應算法效率 6 6、時間複雜度與「大O記法」 7 7、時間複雜度 8 8、時間複雜度的引入 9 9、引入表示時間複雜度的特徵 10 10、大O表示法 11 11、最壞時間複雜度 12 12、時間複雜度的集中基本計算規則 13 13、常見時間複雜度
數據結構和算法在開發中是有序優化性能的時候的必備利器。算法
數據結構和算法的做用:服務器
若是沒有數據結構和算法,有時候面對問題可能會沒有任何思路不知道如何下手,或許大部分時間都能解決問題,但是程序的運行效率和開銷沒有意識,性能低下。數據結構
因此數據結構和算法是一個開發人員的必備基本功不是一朝一夕就能練成的,須要平時不斷的去學習和積累。數據結構和算法
算法概念:ide
算法是計算機處理信息的本質,由於計算機程序本質上是一個算法告訴計算機確切的步驟來執行一個指定的任務,通常來講,當一個算法在處理信息的時候,會從輸入設備或者數據的存儲地址讀取數據,把結果寫到輸出設備或者某個存儲地址之後再調用函數
若是a+b+c=100,而且a^2+b^2=c^2(a,b,c都是天然數),求出a、b、c可能的組合性能
解析:學習
首先想到的多是枚舉法優化
用枚舉法:spa
a=0
b=0
c=1
或者
a=0
b=1
c=1
等等這樣來試驗
代碼以下:
import time start_time=time.time() for a in range(0,101): for b in range(0,101): for c in range(0,101): if a+b+c==100 and a**2+b**2==c**2: print("a,b,c:%d,%d,%d"%(a,b,c)) end_time=time.time() print("time:%s" %(end_time-start_time)) #time:0.17448711395263672 print("finish")
其實還能夠進行優化:
import time start_time=time.time() for a in range(0,101): for b in range(0,101-a): c =100- a- b if a**2+b**2==c**2: print("a,b,c:%d,%d,%d"%(a,b,c)) end_time=time.time() print("time:%s" %(end_time-start_time)) #time:0.006990909576416016 print("finish")
這個優化解析:這裏因爲a和b不能相同,因此能夠少一個循環遍歷
而後兩種程序時間結果對比,能夠看出兩個程序的效率
一、 輸入:算法具備0個或者多個輸入
二、 輸出:算法至少有一個或者多個輸出
三、 有窮形:算法在有限的步驟以後就會自動結束而不會無限循環,而且每個步驟能夠在可接受的時間內完成
四、 肯定性:算法中的每一步都是有肯定含義的,不會出現二義性
五、 可行性:算法的每一步都是可行的,也就是說每一步都可以執行有限的次數完成
對於上面的同一個問題,給出了兩種解決算法,在兩種算法的實現中,咱們對程序執行的時間進行了測算,發現兩端程序的時間相差懸殊,得出結論:實現算法的程序的執行時間能夠反映出算法的效率,即算法的優劣
單靠時間之絕對可靠嗎?
若是一段程序跑在不一樣的機器上面,時間是不同的,所以單靠執行的時間來比較算法的優秀與否,並不必定是客觀準確的!程序的運行離不開計算機環境(包括硬件和操做系統)這些客觀緣由會影響程序運行的速度而且反應在程序的執行時間上。
每臺機器執行的總時間不一樣,可是執行基本運算數量和答題是相同的
什麼是時間複雜度?
每臺機器運行的總時間就是基本運行數量乘於每個基本步驟完成的時間
每臺機器運行的總時間==基本運行數量×每個基本步驟完成的時間
基本運行數量的總和 就是時間複雜度
咱們把算法執行時間效率的快慢 稱之爲 時間複雜度
時間複雜度怎麼去描述?
咱們用一個程序執行到底通過了多少個基本運算數量來描述時間複雜度
引入上面的程序:
import time start_time=time.time() for a in range(0,101): for b in range(0,101): for c in range(0,101): if a+b+c==100 and a**2+b**2==c**2: print("a,b,c:%d,%d,%d"%(a,b,c)) end_time=time.time() print("time:%s" %(end_time-start_time)) #time:0.17448711395263672 print("finish")
這裏咱們讓時間複雜度叫作T
上面這個程序的時間複雜度爲多少?
第一次循環要作100次
第二次循環又要作100次
第三層循環也要作100次
第四層 細化要作10次,若是不細化,就是兩句話
T=100*100*100*2
若是讓上面的程序更改成a+b+c=200
T=200*200*200*2
若是是該爲n
T=n*n*n*2
這類問題和規模n有關係T(n)
上面的時間複雜度就是
T(n)=n^3*2
咱們就把T(n)就叫作這個程序的時間複雜度
咱們能夠把
T(n)=n^3*2
T(n)=n^3*10
上面的函數同一個數量級的也就是和T(n)=n^3 是同一個數量級的
好比服務器用的是T這個數量級,而不去關注是多少T,之前的mp3是M的數量級,而不去關心是多少M
也就是上面T(n)=n^3*10 的10這個係數隻影響走勢
T(n)=n^3*10+10
g(n)=n^3
T(n)=k* g(n)
T(n)和g(n)相差的就是常量 k,這個時候咱們就說g函數是T函數的漸進函數
詳細解釋:
「大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)
咱們用提出來的g(n)(可以表示出時間複雜度的特徵)就叫作一個時間複雜度的大O表示法
其實就是 可以表示時間複雜度特徵 就表示時間複雜度的大O表示法
T(n)=O(g(n))
詳細解釋:
對於算法進行特別具體的細緻分析雖然很好,但在實踐中的實際價值有限。對於算法的時間性質和空間性質,最重要的是其數量級和趨勢,這些是分析算法效率的主要部分。而計量算法基本操做數量的規模函數中那些常量因子能夠忽略不計。例如,能夠認爲3n2和100n2屬於同一個量級,若是兩個算法處理一樣規模實例的代價分別爲這兩個函數,就認爲它們的效率「差很少」,都爲n2級。
一、 基本操做,只有常數項,認爲其時間複雜度爲O(1)
二、 順序結構,時間複雜度按加法進行計算
三、 循環結構,時間複雜度按懲罰進行計算
四、 分支結構,時間複雜度取最大值
五、 判斷一個算法的效率的時候,每每只須要關心操做數量的最高次項,其餘次要項和常數項能夠忽略
六、 在沒有特殊說明的時候咱們分析的算法的時間複雜度都是指的最壞時間複雜度
所以咱們把咱們優化的程序的時間複雜度爲:
import time start_time=time.time() for a in range(0,101): for b in range(0,101-a): c =100- a- b if a**2+b**2==c**2: print("a,b,c:%d,%d,%d"%(a,b,c)) end_time=time.time() print("time:%s" %(end_time-start_time)) #time:0.006990909576416016 print("finish")
T(n)=n*n*(1+max(1,0))
=2n^2
所以這個程序的時間複雜度爲O(n^2)
執行次數函數舉例 |
階 |
非正式術語 |
12 |
O(1) |
常數階 |
2n+3 |
O(n) |
線性階 |
3n2+2n+1 |
O(n2) |
平方階 |
5log2n+20 |
O(logn) |
對數階 |
2n+3nlog2n+19 |
O(nlogn) |
nlogn階 |
6n3+2n2+3n+4 |
O(n3) |
立方階 |
2n |
O(2n) |
指數階 |
注意,常常將log2n(以2爲底的對數)簡寫成logn
所消耗的時間從小到大:
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)