算法中的复杂度分析
復(fù)雜度
前言
來(lái)復(fù)習(xí)下,算法體重經(jīng)常聊到的復(fù)雜度
算法中我們經(jīng)常會(huì)從兩個(gè)角度去考慮算法的優(yōu)劣,那就是【時(shí)間維度】和【空間維度】
時(shí)間復(fù)雜度
時(shí)間復(fù)雜度:就是執(zhí)行當(dāng)前算法消耗的時(shí)間。
當(dāng)然我們這里講的時(shí)間復(fù)雜度是個(gè)更加通用的描述,因?yàn)槲覀冎来a在不同中機(jī)器中執(zhí)行的時(shí)間是不同的,性能好的機(jī)器可能就用的時(shí)間更短。
所以我們這里的時(shí)間復(fù)雜度,用的是【大O符號(hào)表示法】,即T(n) = O(f(n))
如何理解呢?先來(lái)個(gè)栗子
func sum(n int) int {sum :=0i:=3for m:=0;m<n;m++ {sum+=n*i+1}return sum }比如上面這段代碼,循環(huán)了n次,那么時(shí)間復(fù)雜度就是O(n),如何分析呢?
我們假定每行代碼執(zhí)行的時(shí)間是一個(gè)時(shí)間顆粒,那我們上面的例子,第2和3行一共兩個(gè)時(shí)間顆粒,4和5行就是2*n個(gè)時(shí)間顆粒,總共就是(2n+2)個(gè)時(shí)間顆粒。
當(dāng)然這樣算下來(lái)時(shí)間復(fù)雜度是T(n) = O(2n+2),大 O 時(shí)間復(fù)雜度實(shí)際上并不具體表示代碼真正的執(zhí)行時(shí)間,而是表示代碼執(zhí)行時(shí)間隨數(shù)據(jù)規(guī)模增長(zhǎng)的變化趨勢(shì),所以,也叫作漸進(jìn)時(shí)間復(fù)雜度(asymptotic time complexity),簡(jiǎn)稱(chēng)時(shí)間復(fù)雜度。
如果 n 很大時(shí),而公式中的低階、常量、系數(shù)三部分并不左右增長(zhǎng)趨勢(shì),所以都可以忽略。也就是2n中的2和常量2都可以忽略,所以時(shí)間復(fù)雜度就是T(n) = O(n)
常數(shù)階O(1)
無(wú)論代碼執(zhí)行了多少行,只要是沒(méi)有循環(huán)等復(fù)雜結(jié)構(gòu),那這個(gè)代碼的時(shí)間復(fù)雜度就都是O(1),如:
func sum(n int) int {sum :=0i:=3sum=sum*ireturn sum }因?yàn)檫@段代碼中沒(méi)有一個(gè)系數(shù),會(huì)導(dǎo)致代碼的執(zhí)行時(shí)間隨系數(shù)的變化而變化,所以不管這個(gè)代碼有多少行,都可以時(shí)間復(fù)雜度是 O(1)
一般情況下,只要算法中不存在循環(huán)語(yǔ)句、遞歸語(yǔ)句,即使有成千上萬(wàn)行的代碼,其時(shí)間復(fù)雜度也是Ο(1)。
線性階O(n)
比如我們剛開(kāi)始的這個(gè)例子
func sum(n int) int {sum :=0i:=3for m:=0;m<n;m++ {sum+=n*i+1}return sum }代碼中有個(gè) for 循環(huán),代碼的執(zhí)行時(shí)間會(huì)因?yàn)?n 的變化而變化,并且是線性增加或減少,所以這里用 O(n) 來(lái)表示他的時(shí)間復(fù)雜度。
對(duì)數(shù)階O(logN)
func sum(n int) int {sum :=0for sum<n {sum+=n*2}return sum }這里同樣也是一個(gè)循環(huán),只不過(guò)每次都乘以2。也就是2的 x 次方大于等于 n 。 執(zhí)行的次數(shù)就是 x 。
接著上面轉(zhuǎn)換的結(jié)果,對(duì)于省略掉常數(shù)2,所以時(shí)間復(fù)雜度就是 O(logN)
實(shí)際上,不管是以2為底、以3為底,還是以10為底,我們可以把所有對(duì)數(shù)階的時(shí)間復(fù)雜度都記為 O(logn)
線性對(duì)數(shù)階O(nlogN)
將上面的代碼實(shí)例,外面在循環(huán) n 次,時(shí)間復(fù)雜度就是下面我們要討論的 O(nlogN)
func sum(n int) int {sum :=0for i:=0;i<n;i++{for sum<n {sum+=n*2}}return sum }這個(gè)就不展開(kāi)討論了,內(nèi)層循環(huán)是上面我們討論的 O(logN) ,外面多了一層循環(huán),所以時(shí)間復(fù)雜度就是 O(nlogN)
平方階O(n2)
這個(gè)就很好理解了,就是兩層代碼的循環(huán)
func sum(m,n int) int {sum :=0for i:=0;i<m;i++{for j:=0;j<n;j++ {sum+=j}}return sum }當(dāng)然有三層循環(huán)就是 O(n3),依次類(lèi)推
空間復(fù)雜度
空間復(fù)雜度全稱(chēng)就是漸進(jìn)空間復(fù)雜度(asymptotic space complexity),表示算法的存儲(chǔ)空間與數(shù)據(jù)規(guī)模之間的增長(zhǎng)關(guān)系。
來(lái)個(gè)栗子分析下
func test(n int) map[int]struct{} {testMap := make(map[int]struct{}, n)for i := 0; i < n; i++ {testMap[i] = struct{}{}}return testMap }比如上面的這段代碼,空間復(fù)雜度是 O(n)
我們可以看到 for 開(kāi)始的時(shí)候申請(qǐng)了一個(gè)變量 i ,這是常量級(jí)別的,跟數(shù)據(jù)規(guī)模 n 沒(méi)有關(guān)系,所以我們可以忽略。我們初始化了一個(gè)長(zhǎng)度為 n 的 testMap。testMap 的長(zhǎng)度會(huì)根據(jù) n 的變化而變化,所以這段代碼的空間復(fù)雜度就是 O(n)。
常數(shù)階O(1)
這個(gè)很簡(jiǎn)單
func sum(n int) int {sum :=0i:=3sum=sum*ireturn sum }因?yàn)闆](méi)有變量跟隨數(shù)據(jù)規(guī)模 n 的變化而變化,所以空間復(fù)雜度就是 O(1)。
平方階O(n2)
看個(gè)栗子
func test(n int) [][]int {var sil = make([][]int, n)for i := 0; i < n; i++ {for j := 0; j < n; j++ {sil[i] = append(sil[i], j)}}return sil }定義了二維切片,隨著兩層循環(huán),分別申請(qǐng)了 n*n 個(gè)空間的大小,所以空間復(fù)雜度就是 O(n2)
當(dāng)然有二維切片就是 O(n3),依次類(lèi)推
最好、最壞情況時(shí)間復(fù)雜度
最好情況時(shí)間復(fù)雜度就是,在最理想的情況下,執(zhí)行這段代碼的時(shí)間復(fù)雜度。
最壞情況時(shí)間復(fù)雜度就是,在最糟糕的情況下,執(zhí)行這段代碼的時(shí)間復(fù)雜度。
比如這段代碼
func sum(n, m int) int {sum := 0for i := 0; i < n; i++ {if sum == m {return sum}sum += i * 2}return sum }如果在第一次循環(huán)的時(shí)候,sum == m?就結(jié)束程序,那么這個(gè)時(shí)候的時(shí)間復(fù)雜度就是最好時(shí)間復(fù)雜度。
當(dāng)然如果上面的 for 循環(huán),遍歷到最后一次也沒(méi)滿足?sum == m,那么這個(gè)時(shí)候的時(shí)間復(fù)雜度就是最壞情況時(shí)間復(fù)雜度。
平均情況復(fù)雜度
顧名思義就是,最好和最壞的時(shí)間復(fù)雜度的平均值。
比如上面的那個(gè)例子
引入概率之后,前面那段代碼的加權(quán)平均值為(3n+1)/4。用大O表示法來(lái)表示,去掉系數(shù)和常量,這段代碼的加權(quán)平均時(shí)間復(fù)雜度仍然是O(n)。
均攤時(shí)間復(fù)雜度
對(duì)一個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行一組連續(xù)操作中,大部分情況下時(shí)間復(fù)雜度都很低,只有個(gè)別情況下時(shí)間復(fù)雜度比較高,而且這些操作之間存在前后連貫的時(shí)序關(guān)系,這個(gè)時(shí)候,我們就可以將這一組操作放在一塊兒分析,看是否能將較高時(shí)間復(fù)雜度那次操作的耗時(shí),平攤到其他那些時(shí)間復(fù)雜度比較低的操作上。而且,在能夠應(yīng)用均攤時(shí)間復(fù)雜度分析的場(chǎng)合,一般均攤時(shí)間復(fù)雜度就等于最好情況時(shí)間復(fù)雜度。
其實(shí)也可以認(rèn)為均攤時(shí)間復(fù)雜度就是一種特殊的平均時(shí)間復(fù)雜度。
總結(jié)
這里大概介紹了空間復(fù)雜度和時(shí)間復(fù)雜度
時(shí)間復(fù)雜度的全稱(chēng)是漸進(jìn)時(shí)間復(fù)雜度,表示算法的執(zhí)行時(shí)間與數(shù)據(jù)規(guī)模之間的增長(zhǎng)關(guān)系。類(lèi)比一下,空間復(fù)雜度全稱(chēng)就是漸進(jìn)空間復(fù)雜度(asymptotic space complexity),表示算法的存儲(chǔ)空間與數(shù)據(jù)規(guī)模之間的增長(zhǎng)關(guān)系。
這里的計(jì)算使用的是【大 O 復(fù)雜度表示法】,時(shí)間復(fù)雜度和空間復(fù)雜度只和數(shù)據(jù)規(guī)模 n 有關(guān)系,公式中的低階、常量、系數(shù)三部分不影響增加趨勢(shì),所以不收這三個(gè)的影響。
總結(jié)
- 上一篇: 树莓派使用python+继电器控制220
- 下一篇: 一次OutOfMemoryError: