我知道的時間複雜度與空間複雜度

做者前言

你們好,我是阿濠,今篇內容跟你們分享的是數據結構裏的時間複雜度與空間複雜度,很高興分享到segmentfault與你們一塊兒學習交流,初次見面請你們多多關照,一塊兒學習進步.很是感謝小甲魚的視頻教學,學到不少

1、算法的效率的度量方法

咱們設計算法的時候,要儘可能提升效率,這裏的效率指的是算法的執行時間算法

那麼咱們如何來度量一個算法的執行時間呢?segmentfault

簡單的方法則是把算法跑若干次,而後拿個計時器計時,求出平均時間,這是馬拉松的求法,這是過後統計方法,固然咱們也不須要真的那個計時器來算。由於咱們可使用計算機來幫咱們算嘛數組

過後統計法:

1.準備好設計好的測試程序和數據
2.經過利用計算機計時器對不一樣算法編制的程序的運行時間
3.講運行時間進行比較,從而肯定算法的效率高低數據結構

可是這種方法是有很大的缺陷的
1.必須依據算法實現編制測試的程序,這就要花費大量時間和精力
2.測試完發現這是一個糟糕的算法,那不是功虧一簣了?
3.不一樣的測試環境(電腦性能等)差異不是通常的大!函數

爲了對算法評估更爲科學和便捷,有的前輩研究出了事前分析估算的方法性能

事前估算的法:

在計算機程序編寫前,依據統計方法對算法進行估算,咱們發現一個高級程序語言編寫的程序在運行所消耗的時間取決於如下因素:
1.算法採用的策略、方案
2.編碼產生的代碼質量
3.問題的輸入規模學習

因而可知,拋開這些因素於計算機硬件、軟件相關的問題,一個程序的運行時間依賴於算法的好壞和問題的輸入規模測試

舉個高斯的求值方法1+2+3+4+5...+100案例編碼

普通的第一種算法,一個一個的加spa

圖片.png

假設如果從1+2+3..+1000000的時候?那就須要1000000次,

普通的第二算法,只需加一次

圖片.png

+1000000的時候,也只須要執行一次則能夠得出答案

咱們會發現,第一種算法與第二種算法進行比較的話

1.第一種算法執行了1+(n+1)+n次=2n+2次
2.第二種算法執行了1+1=2次

若是咱們忽略頭和尾,把循環看做一個總體,其實就是n和1的差距

咱們再來看第二個列子

圖片.png

若是要讓i從1走到100 那麼須要每次都先讓j從1走到100次,那麼這種狀況這是100^2次(100的平方)

最終不關心編寫程序所用的語言、也不關心程序跑在什麼計算機上,甚至不計較循環索引和終止循環的條件、聲明變量、打印結果等等操做,只關心所設計的算法或一些列操做,再將基本操做的數量與輸入模式關聯起來

以剛剛的例子用圖來解釋一下

圖片.png

藍線1則是不管數是多大,都將只執行一次
圖片.png

紅線n則是數是多大,就執行屢次

圖片.png

灰線則是數是多大,都將執行平方,好比所你輸入1,則是1*1,輸入2則是2*2,求一百則是100*100
圖片.png

2、函數的漸近增加

作一個測試:如下兩個算法A和B那個更好?

假設兩個算法規模都是輸入n

算法A要先作2n+3次,好比說先執行n次循環,執行完再作一次n次循環,最後再進行三次運算

算法B要先作3n+1次,好比說先執行n次循環,執行完再作一次n次循環,最後再作一次n次循環,再執行一次運算

你以爲是哪一個更快呢?

咱們來作一個表格圖來比較一下

圖片.png

當n=1時,算法A1不如B1
當n=2時,算法A1和B1二者效率相同,
當n>2時,算法A1就比B1,且隨着n增長,算法A和算法B就拉開差距了

圖片.png

從剛纔的對比中,咱們發現隨着n增大,後面的+3或者+1都不影響最終的算法變化曲線的,再圖中,他們壓根就被覆蓋了,因此能夠忽略這些常數

第二個測試,算法C是4n+8,算法D是2N^2+1

圖片.png圖片.png

最終給咱們發現哪怕是去掉常數,那麼4n+8與n就看上去基本平行了,二者的結果仍是沒多大變化,與高次項相乘,常數便可忽略

第三個測試,算法E是2n^2+3n+1,算法F則是2n^3+3n+1
圖片.png

圖片.png

隨着n的增大,咱們能夠看到n^2是比n^3差異是很是大的,這是不可取的

前三個測試,咱們發現高次項的指數大的,隨着n的增加,也會變得很是大,意思就是說n^三、n^2隨着n獲得的數會變得很大

第四個測試,算法G是2n^2,算法H是3n+1,算法I是2n^2+3n+1

圖片.png

發現算法G和算法I,在n等於1000000的時候,執行的數很是的大,而且沒有多少差距,而算法H差很少能夠忽略,沒法進行比較,那麼咱們將數字放小,作一個比較

圖片.png

因而咱們獲得一個結論函數中的常數和其餘次要項經常能夠忽略,因此主要關注的是主項(高次項)

好比說n^2+3n+1 裏n^2是主項、 2n^3+3n+1裏n^3是主項、3n+1裏n是主項

3、算法的時間複雜度

有了前面的鋪墊,那就好講時間複雜度攻略。

算法時間複雜度的定義:
語句總的執行數T(n)是關於問題規模n的函數,進而分析T(n)隨n的變化狀況並肯定T(n)的數量級。算法的時間複雜度,也就算法的時間量度記做:T(n)=O(f(n)),它表示隨着問題規模n的的增大,算法執行時間的增加率相同,稱做算法的漸近時間複雜度,簡稱爲時間複雜度。其中f(n)是問題規模n的某個函數

咱們用大寫O來體現算法時間複雜度的記法,咱們稱爲大O記法

根據前面的測試咱們可知算法時間複雜度分別爲O(1)、O(n)、O(n^2)

圖片.png

推倒大O階方法

有如下思路:
1.用常數1取代運行時間中的全部加法常數
(好比說有三條加法常數指令、八條輸出指令等等這些就用1來代替)就不用說O(幾)多少多少
2.在修改後的運行次數函數中,只留最高次項好比說n^2/n^3
3.若是最高項存在且不是1,則去除與項相乘的常數(好比說3N^2,咱們則只認O(N^2))
4.獲得最後的結果大O階

咱們作幾個錯誤的示範:

圖片.png

這段代碼的大O是多少?O(8)?

O(8)是常犯的錯誤,上面思路提到,輸出指令等等就用1代替,這是與問題規模無關的數據,因此使用O(1)就能夠了

圖片.png

這段代碼的大O是多少?

它的時間複雜度爲O(n),由於循環體中代碼須要執行n次

圖片.png

這段代碼的大O是多少?

n等於100的時候,也就說外層循環執行一次,裏面循環就要執行100次,那莪總共的執行時間則是100*100次,也就是說是n的平方,因此這段代碼時間複雜度爲O(n^2)

若是有三個嵌套循環呢?便是n^3啦,因此咱們總結得出循環的時間複雜度等於循環體的複雜度乘以該循環運行的次數。

圖片.png

這段代碼的大O是多少?

當i=0的時候,內嵌j則作了n次(100次)
當i=1的時候,內嵌j則作了n-1次(99次)1-99
當i-2的時候,內嵌j則作了n-2次(98次)1-98
....找到規律後則是

n+(n-1)+(n-2)+...+1=100+99+98+...+1

是否是很像1+2+3+4+...+100呢?

套用高斯算法後則是n(n+1)/2=(n^2)/2+n/2

按照思路保留最高次項因此n/2去掉,存在最高項且不是1,則去掉與項相乘的常數,最終獲得O(n^2)

圖片.png

這段代碼的大O是多少?

因爲每次都是i=i*2以後,就會離n愈來愈近,i=二、四、八、1六、32....

有沒有發現它好像是n的多少次方噢,假設有x個2相乘,那麼最後會大於或者等於n的,就會結束循環。

因爲2^x=n, x則是咱們的循環次數,即獲得x=log2n 因此循環的時間複雜度爲O(log)n

那麼就會有人問log2n是個什麼東西,爲何2^x=n,x=log2n?

在數學中,log表示對數。

好比2的三次方=8,那麼log2(8)=3就是求2的多少次方等於8

這樣就不難理解了,剛剛咱們的2^x=n,那麼x=log2n,分解出來着是

假設x=1,2^1=2,那麼反過來求x的時候便是x=log2(2),那麼求2的多少次方等於2?答案是x=1

假設x=2,2^2=4,那麼反過來求x的時候便是x=log2(4),那麼求2的多少次方等於4?答案是x=2

假設x=3,2^3=8,那麼反過來求x的時候便是x=log2(8),那麼求2的多少次方等於8?答案是x=3

......

4、函數調用的時間複雜度分析

咱們根據前面的內容,把東西更實際分析理解

圖片.png

咱們來分析一下:
1.function函數裏方法體是輸出語句,即便時間複雜度O(1),爲何?根據思路第一條,輸出指令都一般爲O(1)。
2.for循環則是n=多少就作多少次,因此整體得時間複雜度爲O(n)

圖片.png

咱們來分析一下:
1.function函數裏面方法體有一個循環,便是O(n),那麼外面又有一個循環,也作了O(n)次
2.可是外面的循環作一次,函數裏就要作O(n)次,外面循環作n次,就是即n*n了,因此整體的時間複雜度爲O(n^2)

圖片.png

咱們來分析一下:
1.n++ 按照思路則是O(1)
2.function(n)便是上一個例子裏的O(n^2)
3.for循環裏有fucntion那便是也是O(n^2)
4.兩個for裏即也是O(n^2)

並列起來即便3(n^2)+1,根據咱們的思路則則是O(n^2)爲何?保留最高次項數,去掉常數

5、常見時間複雜度

根據前面的思路,看看錶格信息熟悉熟悉

圖片.png
圖片.png

咱們發現隨着數據的增加,時間差距慢慢就出來了,那麼數據變大的時候呢?

圖片.png

那麼根據前面的列子總結時間複雜度信息,咱們就會發現常見的從小到大順序

O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)

最壞狀況與平均狀況

好比說咱們查找一個有n個隨機數字數組中某個數字,那麼最好的狀況就是第一個數就是咱們要找的,便是O(1),但也有可能須要查找n次才能找到,便是O(n),那麼平均時間便是咱們指望的運行時間

最壞時間即便咱們的保證,一般除非特別指定,咱們獲得的運行時間都是最壞狀況的運行時間

6、算法的空間複雜度

咱們在寫算法時,可使用空間去換時間,或者時間換空間,舉個例子來講咱們判斷某年是否是閏年,你可能花心思來,算每一年的月份裏的信息

另外一種方法則是 事先創建一個有2050個數組,把全部年份按照下標的數字對應,若是是閏年就該數組的元素爲1,若是不是則是0,這樣所謂是否閏年就變成了某一個元素的值

這就所謂的空間換時間了,哪種好?還要看你用在什麼地方

算法的空間複雜度經過計算所須要的存儲空間實現

算法的空間複雜度公式:S(n)=O(f(n))

一般咱們使用時間複雜度來指運行時間的需求,使用空間複雜度指空間需求

相關文章
相關標籤/搜索