通過(guò)js示例講解時(shí)間復(fù)雜度與空間復(fù)雜度
1. 博客背景
今天有同事在檢查代碼的時(shí)候,由于函數(shù)寫(xiě)的性能不是很好,被打回去重構(gòu)了,細(xì)思極恐,今天和大家分享一篇用js講解的時(shí)間復(fù)雜度和空間復(fù)雜度的博客
2. 復(fù)雜度的表示方式
之前有看過(guò)的,你可能會(huì)看到這么一串東西
T(n) = O(f(n)) S(n) = O(f(n))
這個(gè)叫做大O表示法,其中的T代表的是算法需要執(zhí)行的總時(shí)間
S表示的算法需要的總空間
f(n)表示的是代碼執(zhí)行的總次數(shù)
舉個(gè)例子
function go(n) {
var item = 0; // 這里執(zhí)行了一次
for (var i = 0; i < n; i++) { //這里執(zhí)行了N次
for (var j = 0; j < n; j++) { //這里執(zhí)行了n*n次
item = item + i + j; //這里執(zhí)行了n*n次
}
}
return item; //這里執(zhí)行了一次
}
所以說(shuō)上邊這段代碼是 1+n+n*n*2+1=2+n+2n²
也就是說(shuō) T(n) = O(f(2+n+2n²))
然后之前說(shuō)了時(shí)間復(fù)雜度看的是一個(gè)代碼執(zhí)行的時(shí)間的趨勢(shì), 所以說(shuō)在N,也就是規(guī)模比較大的時(shí)候,那些常量是起不到?jīng)Q定性的作用的,所以這個(gè)時(shí)候我們忽略這些常量,這里的例子是一個(gè)單段的代碼,這里只看最大量級(jí)的循環(huán)就可以了
所以最后的這個(gè)代碼的時(shí)間復(fù)雜度是T(n) = O(n²)
大家可以想想一下數(shù)據(jù)中平方的曲線(xiàn)圖
3. 時(shí)間復(fù)雜度
3.1 時(shí)間復(fù)雜度的定義
首先什么是時(shí)間復(fù)雜度,時(shí)間復(fù)雜度這個(gè)定義如果在之前沒(méi)有接觸過(guò)的話(huà),你可能會(huì)認(rèn)為他代表的是一個(gè)代碼執(zhí)行的時(shí)間,其實(shí)不然,算法的時(shí)間復(fù)雜度就是說(shuō)一個(gè)算法的執(zhí)行時(shí)間根據(jù)數(shù)據(jù)規(guī)模增長(zhǎng)的一個(gè)趨勢(shì),并不是說(shuō)代碼執(zhí)行的具體時(shí)間
3.2 幾種常見(jiàn)的時(shí)間復(fù)雜度
最簡(jiǎn)單的O(n)
for (var i = 0; i < n; i++) {
sum += i;
}
通俗易懂,這段代碼的執(zhí)行時(shí)間完全由N來(lái)控制,所以說(shuō)T(n) = O(n)
當(dāng)然還有個(gè)更簡(jiǎn)單的O(1)
function total(n) {
console.log(1)
}
無(wú)論怎么樣,這段函數(shù)不受任何參數(shù)影響,代碼走一遍就完事,這種的代碼用T(n) = O(1) 表示
T(n) = O(n²)
上邊的例子已經(jīng)說(shuō)了一個(gè)了兩層循環(huán)的那種,在舉一個(gè)時(shí)間復(fù)雜度多塊代碼的情況時(shí)間復(fù)雜度的計(jì)算方式
function go(i) {
var sum = 0;
for (var j = 0; j < i; j++) {
sum += i;
}
return sum;
}
function main(n) {
var res = 0;
for (var i = 0; i < n; i++) {
res = res + go(i); // 這里是重點(diǎn)
}
}
在上邊的代碼種第二段代碼里邊調(diào)用了第一段代碼,所以說(shuō)在這個(gè)代碼里邊是
go:(1+n)
在main函數(shù)里邊的時(shí)候是(1+n*go)=(1+n+n*n)
所以最后的時(shí)間復(fù)雜度是T(n) = O(n²)
3.3 多塊代碼的時(shí)間復(fù)雜度
上邊距離說(shuō)明的T(n) = O(n²) ,是一個(gè)函數(shù)在另一個(gè)函數(shù)里邊被調(diào)用,這種情況是被把兩個(gè)函數(shù)的時(shí)間復(fù)雜度相乘。
還有另外一種情況,就是說(shuō)在一個(gè)函數(shù)里邊有多塊代碼,但是并沒(méi)有被相互調(diào)用,那么這種情況的時(shí)候,我們只需要取復(fù)雜度最大的代碼塊就可以了
比如說(shuō)
function go(n) {
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
console.log(1)
}
}
for (var i = 0; i < n; i++) {
console.log(2)
}
}
上邊這塊代碼中,第一塊代碼有兩層循環(huán),通過(guò)上邊的例子我們已經(jīng)得知復(fù)雜度是
n²
下邊這塊代碼,是n
那么在這種情況的時(shí)候,當(dāng)N接近無(wú)限大的時(shí)候N是對(duì)n²起不到?jīng)Q定性作用的,所以上邊這塊代碼的時(shí)間復(fù)雜度就是取最大值的n²
3.4 對(duì)數(shù)階和相加情況
var i = 1;
while (i <= n) {
i = i * 10;
}
在這段代碼中,可以看到while里邊,作為判斷條件的i被每次*10,那么所以說(shuō)最后循環(huán)的次數(shù)并不是n次,而是說(shuō)十分之一n次,所以說(shuō)這個(gè)時(shí)候的時(shí)間復(fù)雜度是10i=n,
i=logn
所以得出結(jié)論就是時(shí)間復(fù)雜度是T(n)=O(logn)
然后還有一種情況就是通過(guò)改變的變量去增加循環(huán)次數(shù)的,同理是增加了時(shí)間復(fù)雜度
還有一些其他的情況比如時(shí)間復(fù)雜度相加
function go(m,n) {
for (var i = 0; i < n; i++) {
console.log(1)
}
for (var i = 0; i < m; i++) {
console.log(2)
}
}
請(qǐng)看上邊這一段,這段代碼里邊一個(gè)函數(shù)里邊有兩個(gè)循環(huán),但是形參有兩個(gè),我們現(xiàn)在無(wú)法得知n和m到底誰(shuí)大誰(shuí)小,所以說(shuō)這個(gè)時(shí)候代碼的時(shí)間復(fù)雜度是O(m+n)
4. 空間復(fù)雜度
4.1 空間復(fù)雜度的定義
上邊說(shuō)了那么一大堆的時(shí)間復(fù)雜度,相比各位已經(jīng)比較了解了,就名字來(lái)看,時(shí)間復(fù)雜度看的是代碼的執(zhí)行時(shí)間的趨勢(shì),那么同理的,空間復(fù)雜度就是指的占用內(nèi)存的趨勢(shì)
4.2 常見(jiàn)的空間復(fù)雜度
空間復(fù)雜度沒(méi)有時(shí)間復(fù)雜度那么復(fù)雜,常見(jiàn)的就那么幾種
畢竟我感覺(jué)不會(huì)有人一直循環(huán)著各種花樣的聲明變量吧。。。
如果有,那么請(qǐng)打死。。。。
- O(1)
let a = 1; let b = 1; let c = 1; let d = 1;
很簡(jiǎn)單,O(1)
- O(n)
let arr =Array(n)
看這句代碼,代碼中創(chuàng)建了一個(gè)n長(zhǎng)度的數(shù)組,很明顯數(shù)組的長(zhǎng)度根據(jù)n來(lái)決定,所以說(shuō)
O(n)
這里需要說(shuō)明一下,這里沒(méi)有用循環(huán),是因?yàn)橹灰皇窃谘h(huán)里邊不停的聲明變量,只改變值的話(huà)是不會(huì)層架空間復(fù)雜度的
- O(n²)
let arr=[]
for (var i = 0; i < n; i++) {
arr[i]=i
for (var j = 0; j < n; j++) {
arr[i][j]=j
}
}
怎么樣,猛的一看這個(gè)代碼是不是很刺激,我覺(jué)得如果有這種情況的話(huà),一般都會(huì)被亂棍打死了。。。
復(fù)雜度的優(yōu)化
再說(shuō)優(yōu)化之前我先盜一張圖給大家看一下各個(gè)復(fù)雜度的曲線(xiàn)圖,方便大家有一個(gè)直觀的認(rèn)識(shí)

舉個(gè)比較簡(jiǎn)單的優(yōu)化的例子
console.time('a')
function go(n) {
var item = 0;
for (var i = 1; i <= n; i++) {
item += i;
}
return item;
}
console.timeEnd('a')
console.time('b')
function go2(n) {
var item = n*(n+1)/2
return item;
}
console.timeEnd('b')
go(1000)
go2(1000)
大家可以打印一下看一下
希望大家原諒我數(shù)學(xué)不好,記得之前看到過(guò)一個(gè)等差數(shù)列的例子,想不到其他的性能優(yōu)化的例子
希望大家看完之后可以了解這些概念,有的時(shí)候這個(gè)東西真的很重要,找一個(gè)曲線(xiàn)比較高的例子
斐波那契,就是從第三項(xiàng)開(kāi)始依次等于前兩項(xiàng)的和
斐波那契定義
function Fibonacci(n) {
if (n <= 1 ) {
return n;
} else {
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
}
console.time('b')
Fibonacci(????)
console.timeEnd('b')
有興趣的可以試試打印一下,看看時(shí)間,不過(guò)大概50次的時(shí)候你得瀏覽器就應(yīng)該沒(méi)有響應(yīng)了,具體請(qǐng)往上看曲線(xiàn)圖。。。。
以上是我對(duì)時(shí)間復(fù)雜度和空間復(fù)雜度的一些認(rèn)識(shí),有不足或者不對(duì)的地方,希望指出來(lái)
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
微信小程序?qū)崿F(xiàn)tabbar凹凸圓選中動(dòng)畫(huà)效果實(shí)例
小程序日益增多的情況下,UI風(fēng)格顯得越來(lái)越重要,下面這篇文章主要給大家介紹了關(guān)于微信小程序?qū)崿F(xiàn)tabbar凹凸圓選中動(dòng)畫(huà)效果的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
js實(shí)現(xiàn)圖片輪播效果學(xué)習(xí)筆記
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)圖片輪播效果的學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
js實(shí)現(xiàn)鍵盤(pán)控制DIV移動(dòng)的方法
這篇文章主要介紹了js實(shí)現(xiàn)鍵盤(pán)控制DIV移動(dòng)的方法,以實(shí)例形式完整的講述了js控制div移動(dòng)所涉及的css、js與html使用技巧,需要的朋友可以參考下2015-01-01
js 實(shí)現(xiàn)watch監(jiān)聽(tīng)數(shù)據(jù)變化的代碼
這篇文章主要介紹了js 實(shí)現(xiàn)watch監(jiān)聽(tīng)數(shù)據(jù)變化的代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10
JavaScript中的數(shù)據(jù)類(lèi)型有哪些
本文介紹了JavaScript中的八種數(shù)據(jù)類(lèi)型:Undefined、Null、Boolean、Number、String、Symbol、BigInt和Object,基礎(chǔ)數(shù)據(jù)類(lèi)型存儲(chǔ)在棧內(nèi)存中,而引用數(shù)據(jù)類(lèi)型存儲(chǔ)在堆內(nèi)存中,每種數(shù)據(jù)類(lèi)型都有其特定的用途和特性2025-01-01
js獲取異步函數(shù)數(shù)據(jù)的實(shí)現(xiàn)
本文主要介紹了js獲取異步函數(shù)數(shù)據(jù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
JavaScript驗(yàn)證圖片類(lèi)型(擴(kuò)展名)的函數(shù)分享
這篇文章主要介紹了JavaScript驗(yàn)證圖片類(lèi)型的函數(shù)分享,需要的朋友可以參考下2014-05-05
完美解決手機(jī)網(wǎng)頁(yè)中輸入框被輸入法遮擋的問(wèn)題
下面小編就為大家分享一篇完美解決手機(jī)網(wǎng)頁(yè)中輸入框被輸入法遮擋的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
javascript當(dāng)中的代碼嗅探擴(kuò)展原生對(duì)象和原型(prototype)
如果不是有特殊需要而去擴(kuò)展原生對(duì)象和原型(prototype)的做法是不好的,除非這樣做是值得的,例如,向一些舊的瀏覽器中添加一些ECMAScript5中的方法2013-01-01

