摘要:第三段,時(shí)間復(fù)雜度。五空間復(fù)雜度分析空間復(fù)雜度的話和時(shí)間復(fù)雜度類似推算。
一、前言
時(shí)間復(fù)雜度和空間復(fù)雜度,我們?cè)诖髮W(xué)里的算法與數(shù)據(jù)結(jié)構(gòu)課程中已經(jīng)學(xué)習(xí)過,這回根據(jù)項(xiàng)目工作中整理一下,這個(gè)估計(jì)只是一個(gè)粗略的估計(jì)分析,并不是一個(gè)準(zhǔn)確的估計(jì)分析。
1、學(xué)習(xí)時(shí)間復(fù)雜度和空間復(fù)雜度是很有必要的,這個(gè)屬于算法與數(shù)據(jù)結(jié)構(gòu)的范疇,學(xué)這個(gè)是為了解決代碼中的“快”和“省”的問題。這樣才能使你的代碼運(yùn)行效率更高,占用空間更小。代碼執(zhí)行效率需要通過復(fù)雜度分析。
2、數(shù)據(jù)規(guī)模的大小會(huì)影響到復(fù)雜度分析。比如排序,如果是一個(gè)有序的數(shù)組,執(zhí)行效率會(huì)更高;如果數(shù)據(jù)量很少的時(shí)候,這個(gè)算法看不出性能上差別。
3、比如說不同物理機(jī)環(huán)境不一樣,比如i3,i5,i7的cpu等等,運(yùn)行內(nèi)存1G,2G,4G,8G等等;時(shí)間上肯定有差別。
二、大O的復(fù)雜度我們來看個(gè)簡(jiǎn)單的例子,一個(gè)循環(huán)累加器。
function total(n) { var sum = 0; //t for (var i = 0; i < n; i++) { // nt sum += i; //nt } return sum; // t }
分析:假設(shè)每一行代碼執(zhí)行耗時(shí)都一樣,為t,這樣整個(gè)代碼總執(zhí)行時(shí)間為(t+nt+nt+t)=(2n+2)t。
我們?cè)賮砜匆粋€(gè)栗子:
function total(n) { var sum = 0; // t for (var i = 0; i < n; i++) { //nt for (var j = 0; j < n; j++) { //n*n*t sum = sum + i + j; //n*n*t } } return sum; //t }
分析:假設(shè)每一行代碼執(zhí)行耗時(shí)都一樣,為t,這樣整個(gè)代碼總執(zhí)行時(shí)間為(t+nt+nnt2+t)=(2nn+n+2)t。
從數(shù)學(xué)角度來看,我們可以得出個(gè)規(guī)律:代碼的總執(zhí)行時(shí)間 T(n) 與每行代碼的執(zhí)行次數(shù)成正比.
所以上邊兩個(gè)函數(shù)的執(zhí)行時(shí)間可以標(biāo)記為 T(n) = O(2n+2) 和 T(n) = O(2n*n+n+2)。這就是大 O 時(shí)間復(fù)雜度表示法,它不代表代碼真正的執(zhí)行時(shí)間,而是表示代碼隨數(shù)據(jù)規(guī)模增長(zhǎng)的變化趨勢(shì),簡(jiǎn)稱時(shí)間復(fù)雜度。
而且當(dāng) n 很大時(shí),我們可以忽略常數(shù)項(xiàng),只保留一個(gè)最大量級(jí)即可。所以上邊的代碼執(zhí)行時(shí)間可以簡(jiǎn)單標(biāo)記為 T(n) = O(n) 和 T(n) = O(n2)。
三、時(shí)間復(fù)雜度分析 1、循環(huán)次數(shù)最多的代碼塊在分析的時(shí)候,只需要關(guān)心哪個(gè)代碼塊循環(huán)次數(shù)最多的那段代碼,比如說剛才的第一個(gè)例子,循環(huán)最多的代碼塊是這兩行,循環(huán)都是n次。
for (var i = 0; i < n; i++){ sum += i; }
執(zhí)行了n次,所以事件復(fù)雜度就是O(n)。
2、最大值原則:總復(fù)雜度等于最大的代碼塊的復(fù)雜度function total(n) { // 第一個(gè) for 循環(huán) var sum1 = 0; for (var i = 0; i < n; i++) { for (var j = 0; j < n; j++) { sum1 = sum1 + i + j; } } // 第二個(gè) for 循環(huán) var sum2 = 0; for(var i=0;i<1000;i++) { sum2 = sum2 + i; } // 第三個(gè) for 循環(huán) var sum3 = 0; for (var i = 0; i < n; i++) { sum3 = sum3 + i; } return {sum1:sum1, sum2: sum2, sum3:sum3} }
分別分析每一段循環(huán)時(shí)間復(fù)雜度,取他們最大的量級(jí)決定整段代碼復(fù)雜度。
第一段,時(shí)間復(fù)雜度 O(n2)。
第二段,時(shí)間復(fù)雜度可以忽略,循環(huán)執(zhí)行了 1000 次,是個(gè)常數(shù)量級(jí),盡管對(duì)代碼的執(zhí)行時(shí)間會(huì)有影響,但是當(dāng) n 無限大的時(shí)候,就可以忽略。
第三段,時(shí)間復(fù)雜度O(n)。
綜上所述,所以上述代碼的時(shí)間復(fù)雜度為 O(n2)。
3、乘法原則:嵌套代碼復(fù)雜度等于嵌套內(nèi)外代碼復(fù)雜度乘積舉個(gè)例子:
function f(i) { var sum = 0; for (var j = 0; j < i; j++) { sum += i; } return sum; } function total(n) { var res = 0; for (var i = 0; i < n; i++) { res = res + f(i); // 調(diào)用 f 函數(shù) } }
分析一下:total方法時(shí)間復(fù)雜度O(n),f方法的時(shí)間復(fù)雜度O(n)。
所以整段代碼的時(shí)間復(fù)雜度O(n2)。
四、常見的時(shí)間復(fù)雜度分析最高量級(jí)的復(fù)雜度,效率是遞減的
如上圖可以粗略的分為兩類,多項(xiàng)式量級(jí)和非多項(xiàng)式量級(jí)。其中,非多項(xiàng)式量級(jí)只有兩個(gè):O(2n) 和 O(n!) 對(duì)應(yīng)的增長(zhǎng)率如下圖所示
當(dāng)數(shù)據(jù)規(guī)模 n 增長(zhǎng)時(shí),非多項(xiàng)式量級(jí)的執(zhí)行時(shí)間就會(huì)急劇增加,所以,非多項(xiàng)式量級(jí)的代碼算法是非常低效的算法。
1、常數(shù)階復(fù)雜度O(1)O(1) 只是常量級(jí)時(shí)間復(fù)雜度表示法,并不是代碼只有一行,舉個(gè)例子:
function total() { var sum = 0; for(var i=0;i<100;i++) { sum += i; } return sum; }
雖然有這么多行,即使 for 循環(huán)執(zhí)行了 100 次,但是代碼的執(zhí)行時(shí)間不隨 n 的增大而增長(zhǎng),所以這樣的代碼復(fù)雜度就為 O(1)。
2、對(duì)數(shù)階O(logn)和O(nlogn)(1)對(duì)數(shù)階時(shí)間復(fù)雜度的常見代碼如下:
function total1(n) { var sum = 0; var i = 1; while (i <= n) { sum += i; i = i * 2; } } function total2(n) { var sum = 0; for (var i = 1; i <= n; i = i * 2) { sum += i; } }
上面函數(shù)total1和total2有一個(gè)相同點(diǎn):變量 i 從 1 開始取值,每循環(huán)一次乘以 2,當(dāng)大于 n 時(shí),循環(huán)結(jié)束。
所以真正循環(huán)了x次。2x =n;,所以 x = log2n。
所以上面兩個(gè)函數(shù)時(shí)間復(fù)雜度都是 O(log2n)。
(2)我們?cè)谂e個(gè)例子:
function total1(n) { var sum = 0; var i = 1; while (i <= n) { sum += i; i = i * 3; } } function total2(n) { var sum = 0; for (var i = 1; i <= n; i = i * 3) { sum += i; } }
同理可知:這兩個(gè)函數(shù)的時(shí)間復(fù)雜度為 O(log3n) 。
由于我們可以忽略常數(shù),也可以忽略對(duì)數(shù)中的底數(shù),所以在對(duì)數(shù)階復(fù)雜度中,統(tǒng)一表示為 O(logn);那 O(nlogn) 的含義就很明確了,時(shí)間復(fù)雜度 為O(logn) 的代碼執(zhí)行了 n 次。
3、其他復(fù)雜度O(m+n)和O(m*n)舉個(gè)例子:
function total(m,n) { var sum1 = 0; for (var i = 0; i < n; i++) { sum1 += i; } var sum2 = 0; for (var i = 0; i < m; i++) { sum2 += i; } return sum1 + sum2; }
因?yàn)槲覀儫o法評(píng)估 m 和 n 誰的量級(jí)比較大,所以就不能忽略掉其中一個(gè),這個(gè)函數(shù)的復(fù)雜度是有兩個(gè)數(shù)據(jù)的量級(jí)來決定的,所以此函數(shù)的時(shí)間復(fù)雜度為 O(m+n);那么 O(m*n) 的時(shí)間復(fù)雜度類似。
五、空間復(fù)雜度分析空間復(fù)雜度的話和時(shí)間復(fù)雜度類似推算。 所謂空間復(fù)雜度就是表示算法的存儲(chǔ)空間和數(shù)據(jù)規(guī)模之間的關(guān)系。
舉個(gè)例子:
function initArr(n) { var arr = []; for (var i = 0; i < n; i++) { arr[i] = i; } }
時(shí)間復(fù)雜度的推算,忽略掉常數(shù)量級(jí),每次數(shù)組賦值都會(huì)申請(qǐng)一個(gè)空間存儲(chǔ)變量,所以此函數(shù)的空間復(fù)雜度為 O(n)。
常見的空間復(fù)雜度只有 O(1)、O(n)、O(n2)。其他的話很少會(huì)用到。
六、復(fù)雜度優(yōu)化function total(n) { var sum = 0; for (var i = 1; i <= n; i++) { sum += i; } return sum; }
這段代碼我們很容易知道時(shí)間復(fù)雜度 O(n)。
但是我想把復(fù)雜度降一降,降低到常數(shù)階O(1)。
其實(shí)求和怎么求呢?等比數(shù)列,直接用公式,這就說明了數(shù)學(xué)好的人,算法應(yīng)該高level點(diǎn)。
function total(n) { var sum = n*(n+1)/2 return sum; }
上面函數(shù)的時(shí)間復(fù)雜度僅僅為 O(1),在數(shù)據(jù)規(guī)模比較龐大的時(shí)候,下面的函數(shù)是不是明顯比上面的函數(shù)運(yùn)算效率更高呢。
七、總結(jié)分析算法執(zhí)行效率與數(shù)據(jù)規(guī)模之間的增長(zhǎng)關(guān)系,可以粗略的表示,越高階復(fù)雜度的算法,執(zhí)行效率越低。
復(fù)雜度學(xué)習(xí)之后,有時(shí)候可以避免寫出效率低的代碼。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105934.html
摘要:散列表上面的地圖向我們展示了如何用廣度優(yōu)先搜索的思想找到北京到廣州的最短路線。在廣度優(yōu)先搜索中,我們需要用到隊(duì)列的這種思想來實(shí)現(xiàn)查找。建立了下面這個(gè)模型武漢廣州西藏上海上海武漢廣州代碼完整實(shí)現(xiàn),利用遞歸和廣度優(yōu)先搜索的思想實(shí)現(xiàn)。 什么是廣度優(yōu)先搜索? 如果只是是背概念,幼兒園的小朋友都能背下來念給你聽。 假設(shè)看這篇文章的都和我一樣是個(gè)前端工程師,我們要從廣度優(yōu)先搜索(BFS)中學(xué)到什么...
摘要:也就是說,它通過計(jì)算一個(gè)關(guān)于鍵值的函數(shù),將所需查詢的數(shù)據(jù)映射到表中一個(gè)位置來訪問記錄,這加快了查找速度。這個(gè)映射函數(shù)稱做散列函數(shù),存放記錄的數(shù)組稱做散列表。如果對(duì)象沒有該實(shí)例化該處為一對(duì)象如果該不存在就增加一個(gè)數(shù)量 本系列一系列文章的收集關(guān)于javascript中的數(shù)據(jù)結(jié)構(gòu) 如果你對(duì)數(shù)據(jù)結(jié)構(gòu)不太熟悉 可以看這篇文章如果你只想看代碼 可以看這篇文章如果你只想star 可以去這里 什么是數(shù)...
摘要:之所以把計(jì)數(shù)排序桶排序基數(shù)排序放在一起比較,是因?yàn)樗鼈兊钠骄鶗r(shí)間復(fù)雜度都為。動(dòng)畫計(jì)數(shù)排序思想找出待排序的數(shù)組中最大和最小的元素。桶排序計(jì)數(shù)排序能派上用場(chǎng)嗎手機(jī)號(hào)碼有位,范圍太大,顯然不適合用這兩種排序算法。 showImg(https://segmentfault.com/img/bVbuF9e?w=900&h=500); 1. 前言 算法為王。 想學(xué)好前端,先練好內(nèi)功,只有內(nèi)功深厚者...
摘要:小鹿題目假設(shè)你正在爬樓梯。需要階你才能到達(dá)樓頂。你有多少種不同的方法可以爬到樓頂呢注意給定是一個(gè)正整數(shù)。算法思路二種解決思路,第一利用遞歸第二利用動(dòng)態(tài)規(guī)劃。就是因?yàn)橛辛酥貜?fù)元素的計(jì)算,導(dǎo)致了時(shí)間復(fù)雜度成指數(shù)的增長(zhǎng)。 Time:2019/4/12Title:Clibing SrairsDifficulty: EasyAuthor:小鹿 題目:Climbing Stairs You a...
閱讀 2393·2021-09-30 09:47
閱讀 1378·2021-09-28 09:35
閱讀 3259·2021-09-22 15:57
閱讀 2501·2021-09-22 14:59
閱讀 3648·2021-09-07 10:25
閱讀 3081·2021-09-03 10:48
閱讀 3046·2021-08-26 14:14
閱讀 949·2019-08-30 15:55