日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

大O表示法(复杂度分析)

發(fā)布時(shí)間:2023/12/8 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大O表示法(复杂度分析) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

程序 = 數(shù)據(jù)結(jié)構(gòu)?+ 算法?

大O表示法

什么是程序?相信學(xué)過編程的人都知道,程序由數(shù)據(jù)結(jié)構(gòu)和算法構(gòu)成,想要寫出好的的程序,首先得了解數(shù)據(jù)結(jié)構(gòu)和算法。一切脫離數(shù)據(jù)結(jié)構(gòu)和算法的程序設(shè)計(jì)都是耍流氓!

什么樣的程序才是好的程序?好的程序設(shè)計(jì)無外乎兩點(diǎn),"快""省"。"快"指程序執(zhí)行速度快,高效,"省"指占用更小的內(nèi)存空間。這兩點(diǎn)其實(shí)就對(duì)應(yīng)"時(shí)間復(fù)雜度"和"空間復(fù)雜度"的問題。

怎樣分析一個(gè)程序的時(shí)間復(fù)雜度和空間復(fù)雜度?接下來今天的主角就要登場(chǎng)了!"大O表示法"。"大O表示法"表示程序的執(zhí)行時(shí)間或占用空間隨數(shù)據(jù)規(guī)模的增長趨勢(shì)。大O表示法就是將代碼的所有步驟轉(zhuǎn)換為關(guān)于數(shù)據(jù)規(guī)模n的公式項(xiàng),然后排除不會(huì)對(duì)問題的整體復(fù)雜度產(chǎn)生較大影響的低階系數(shù)項(xiàng)常數(shù)項(xiàng)。乍一看這句話可能不好理解,接下來會(huì)詳細(xì)介紹怎么用"大O法"來進(jìn)行時(shí)間和空間復(fù)雜度分析。

時(shí)間復(fù)雜度

時(shí)間復(fù)雜度,又稱"漸進(jìn)式時(shí)間復(fù)雜度",表示代碼執(zhí)行時(shí)間數(shù)據(jù)規(guī)模之間的增長關(guān)系。

Talking is cheap,show me your code!(不BB,看代碼!)

先來看一個(gè)簡單的栗子,來分析下下面這段代碼的時(shí)間復(fù)雜度:

/*** 累加求和* @param n 數(shù)據(jù)規(guī)模 n->∞* @return*/public int sum(int n){int sum = 0;int i = 0;for (;i<n;i++){sum = sum + i;}return sum;}

上面是一個(gè)累加求和的方法,假設(shè)每條語句的執(zhí)行時(shí)間為單位時(shí)間unit_time,那這個(gè)方法對(duì)于數(shù)據(jù)規(guī)模n來說,總的執(zhí)行時(shí)間為多少呢?

很容易看出,第7、8兩行代碼都只執(zhí)行一次,各為unit_time,第9、10兩行代碼都執(zhí)行n次,各為n*unit_time,所以總的時(shí)間相加得T(n)=unit_time+unit_time+n*unit_time+n*unit_time=(2n+2)*unit_time

用f(n)來表示代碼的執(zhí)行次數(shù)和數(shù)據(jù)規(guī)模的關(guān)系,即f(n)=2n+2。當(dāng)n趨近于無窮大時(shí),f(n)中的常數(shù)項(xiàng)對(duì)于整個(gè)公式的值的影響可以忽略,同樣,系數(shù)相比于數(shù)據(jù)規(guī)模n也可以忽略不計(jì)。最后變?yōu)?strong>f(n) = n,即總的執(zhí)行時(shí)間T(n)與數(shù)據(jù)規(guī)模n成正比。上面的分析方法就是"大O表示法"的主要思想,用公式來表示就是:

?

n:數(shù)據(jù)規(guī)模,通俗點(diǎn)說就是函數(shù)中的那個(gè)變量n

f(n):代碼總的執(zhí)行次數(shù)和數(shù)據(jù)規(guī)模的關(guān)系

T(n):代碼的執(zhí)行時(shí)間(并不是代碼實(shí)際的執(zhí)行時(shí)間,這里表示代碼執(zhí)行時(shí)間和數(shù)據(jù)規(guī)模之間的關(guān)系)

看到這大概對(duì)大O分析法有了一定的理解吧!下面來詳細(xì)介紹時(shí)間復(fù)雜度的分析方法。

1.只關(guān)注循環(huán)執(zhí)行次數(shù)最多的那段代碼

拿上面那個(gè)例子來說,第7、8行代碼與數(shù)據(jù)規(guī)模無關(guān),執(zhí)行次數(shù)最多的在第9、10行代碼,所以只需要關(guān)注循環(huán)這一部分。利用大O分析法可以知道上面累加求和例子的代碼時(shí)間復(fù)雜度為O(n).

下面再來看一個(gè)栗子:

/*** 只關(guān)注循環(huán)次數(shù)最多的那一段代碼* @param n 數(shù)據(jù)規(guī)模 n->∞* @return*/public int sums(int n){int sum = 0;int sum1 = 0;int i = 0;int j = 0;for (;i<n;i++){sum = sum + i;}for(;j<2*n;j++){sum1 = sum1 + j;}return sum+sum1;}

依然拿上面累加求和這個(gè)例子,不過這次返回的是數(shù)據(jù)規(guī)模n累加和數(shù)據(jù)規(guī)模2倍累加的和。該方法中有2處循環(huán)部分,第11、12行和第14、15行。可以看出來,這兩處都有循環(huán)的部分,但是下面循環(huán)執(zhí)行次數(shù)比上面多。根據(jù)上面的原則,我們只需要關(guān)注循環(huán)執(zhí)行次數(shù)最多的那部分代碼。按照上面大O分析法可以知道,這段代碼的時(shí)間復(fù)雜度為O(n).

2.加法法則(總復(fù)雜度等于量級(jí)最大的那段代碼的復(fù)雜度

首先,來了解一下量級(jí)的概念。下面是一些常見的復(fù)雜度量級(jí)及其大O法的表示。

常量階(O(1)):代碼片段執(zhí)行時(shí)間不隨數(shù)據(jù)規(guī)模n的增加而增加,即使執(zhí)行次數(shù)非常大,只要與數(shù)據(jù)規(guī)模無關(guān),都算作常量階。記作O(1).

按量級(jí)遞增排序:常量階O(1)) <?對(duì)數(shù)階O(logn) <??線性階O(n)?< 線性對(duì)數(shù)階O(nlogn)?< 平方階O(n2)...立方階O(n3)...k方階 < 指數(shù)階O()?< 階乘階O(n!)?

其中,O()O(n!)非多項(xiàng)式量級(jí),其他的為多項(xiàng)式量級(jí)。我們把時(shí)間復(fù)雜度為非多項(xiàng)式量級(jí)的算法問題叫作NP(Non-Deterministic Polynomial,非確定多項(xiàng)式)問題。

下面請(qǐng)看一段代碼:

/*** 加法法則:總復(fù)雜度等于量級(jí)最大的那段代碼的復(fù)雜度* @param n 數(shù)據(jù)規(guī)模 n->∞* @return*/public int maxItem(int n){// part1: 執(zhí)行1000次循環(huán)int i = 0;int sum1 = 0;for (;i<1000;i++){ sum1 = sum1 +i;}// part2: 執(zhí)行n此循環(huán)int j = 0;int sum2 = 0;for (;j<n;j++){ sum2 = sum2 +j;}// part3: 嵌套執(zhí)行n次循環(huán)int sum3 = 0;for (int k=0;k<n;k++){ for (int l=0;l<n;l++){sum3 = sum3 + l;}}return sum1+sum2+sum3;}

代碼中有三部分,來分別分析每一部分的時(shí)間復(fù)雜度。第一部分循環(huán)執(zhí)行1000次,與數(shù)據(jù)規(guī)模n無關(guān),即使執(zhí)行10000次,100000次都算作常量階,時(shí)間復(fù)雜度為O(1)。

第二部分循環(huán)執(zhí)行n次,與數(shù)據(jù)規(guī)模n成正比,時(shí)間復(fù)雜度是線性階O(n)。

第三部分有兩層循環(huán),每層循環(huán)都執(zhí)行n次,總共執(zhí)行n*n=n2次,時(shí)間復(fù)雜度為平方階O(n2)。

所以這段代碼總的時(shí)間復(fù)雜度記作T(n) = O(1)+O(n)+O(n2),按照加法法則,只取最大量級(jí)的的復(fù)雜度,即整段代碼的時(shí)間復(fù)雜度為O(n2)

3.乘法法則(嵌套代碼復(fù)雜度等于內(nèi)外代碼復(fù)雜度的乘積

依舊來看一段代碼:

/*** 外層方法* @param n 數(shù)據(jù)規(guī)模* @return*/public int outSum(int n){int i = 0;int sum = 0;for (;i<n;i++) {// 這里調(diào)用inSum()方法累加求和sum = sum + inSum(i);}return sum;}/*** 里層方法* @param n 數(shù)據(jù)規(guī)模* @return*/public int inSum(int n){int i = 0;int sum = 0;for (;i<n;i++) {sum = sum + i;}return sum;}

不難分析出,但看外層和里層循環(huán),時(shí)間復(fù)雜度均為O(n)。二者嵌套一起就可以用到乘法法則,總的時(shí)間復(fù)雜度為O(n*n)=O(n2)。其實(shí)這里就是循環(huán)嵌套,總的執(zhí)行次數(shù)為內(nèi)外執(zhí)行次數(shù)的乘積。

空間復(fù)雜度

空間復(fù)雜度,也稱漸進(jìn)空間復(fù)雜度,表示代碼存儲(chǔ)空間數(shù)據(jù)規(guī)模之間的增長關(guān)系。

空間復(fù)雜度相對(duì)于時(shí)間復(fù)雜度來說,要簡單的多了。下面看一個(gè)簡單的栗子:

/*** 空間復(fù)雜度分析* @param n 數(shù)據(jù)規(guī)模*/public void space(int n){int i = 0;int[] arr = new int[n];for (;i<n;i++) {arr[i] = i;}}

第6行申請(qǐng)一個(gè)空間存儲(chǔ)變量i,由于該空間和數(shù)據(jù)規(guī)模無關(guān),屬于常量階的空間復(fù)雜度,可忽略不計(jì)。

第7行申請(qǐng)一個(gè)大小為n的空間存儲(chǔ)數(shù)組arr,空間復(fù)雜度與數(shù)據(jù)規(guī)模成正比,為O(n)。所以整段代碼空間復(fù)雜度就是O(n)。

一般情況下,一個(gè)程序在機(jī)器上執(zhí)行時(shí),除了需要存儲(chǔ)程序本身的指令、常數(shù)、 變量和輸入數(shù)據(jù)外,還需要存儲(chǔ)對(duì)數(shù)據(jù)操作的存儲(chǔ)單元。若輸入數(shù)據(jù)所占空間只取決于問題本身,和算法無關(guān),這樣只需要分析該算法在實(shí)現(xiàn)時(shí)所需的輔助單元即可。若算法執(zhí)行時(shí)所需的輔助空間相對(duì)于輸入數(shù)據(jù)而言是個(gè)常數(shù),則稱此算法為原地工作,空間復(fù)雜度為O(1)。

常用的空間復(fù)雜度就是O(1)。像O(n2)、O(n3)、O(logn)、O(nlogn)這樣的空間復(fù)雜度平時(shí)都用不到。

以上為自己學(xué)習(xí)極客時(shí)間專欄王爭老師的"數(shù)據(jù)結(jié)構(gòu)與算法"的總結(jié),僅供學(xué)習(xí)使用。本人新開的博客,菜鳥一枚,不正確的地方希望大家指出來,一起學(xué)習(xí)進(jìn)步!

?

?

?

?

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的大O表示法(复杂度分析)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。