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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法录 之 复杂度分析。

發布時間:2025/3/14 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法录 之 复杂度分析。 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  一個算法的復雜度可以說也就是一個算法的效率,一般來說分為時間復雜度和空間復雜度。。。

  注意接下來說的均是比較YY的,適用與ACM等不需嚴格分析只需要大致范圍的地方,至于嚴格的算法復雜度分析的那些數學證明,主定理什么的在《算法導論》這本書上有十分詳細的講解,網上應該也會有人寫過,這里就不多說了(其實,是我不會而已o(╯□╰)o。。。)。

  — 到底啥是復雜度呢?先來個栗子。


   小明有10個蘋果,有一天他餓了,然后準備吃掉一個蘋果,但是小明有中二病,他要吃里面重量最大的那個,于是。。。他需要一個找到那個最大的,可是這應該怎么找呢?

   小明要先量一下第一個蘋果多重,然后第二個多重,然后量第三個。。。一直到第十個,量的時候記錄當前最重的那個,然后當找完了這十個就好了。。。

   下面來看看這個神奇的找蘋果算法的復雜度,有10個蘋果,所以需要測量10次才能找到,如果有100個蘋果,顯然需要測量100次,1000個呢,1000次,n個也就需要n次。

   下面設n為問題的規模,f(n)為運算次數,那么對于小明這個問題來說 f(n)=kn,k是一個常數,這個例子 k=1。(看到如此眼熟的高中數學氣息有沒有啥感覺。。。)


?

  — 不用多說就知道如果需要的運算次數多的話,需要花費的時間也就多,所以這就是時間復雜度了,對于上面那個問題的時間復雜度就是 f(n) 了。

  — 但是。。。對于一個問題的常數 k 是比較難搞定的,可能稱一下蘋果的重量需要一步操作,也可能兩步,也可能好幾步。所以對于時間復雜度的分析一般是去找漸進復雜度。簡單說就是函數 f(n) 省略了常數和低次項,只留下最高次項。比如函數 6n^3+3n^2+2n+10 變成了 n^3 ,因為當n很大很大的時候,變化趨勢就是 n^3 型的,再比如 2^n+n^5 就變成了 2^n,因為指數爆炸嘛。。。

  — 這里還要說說符號 O,o 和?Θ,這三個應該高數課會講。。。O( f(n) ) 表示函數的上界,也就是一個一直比 f(n) 大的函數,然后 o 就是下界,至于 ?Θ 的話,叫做中界(我YY的一個名字)?也就是和 f(n) 的增長速度一樣。。。不過一般來說之后的分析都是用 O 的,因為這個字母好寫。。。餓,其實可以理解為因為O是上界,所以算法遇到再壞的情況也不會超過這個函數。

?

?

  — 對于一個算法來說一般常用的漸進復雜度函數有 O( n ) ?O( n^2 ) ?O( n^3 ) ?O(1) ?O( 2^n ) ?O( n!) ?O( log n) ?O( n*logn ) ?O( n*2^n ) 差不多這些,注意 log 指以2為底的對數。。。函數圖就像下面這樣:

  — 然后分別比較看看哪種復雜度更好,顯然 O(1)是最好的,因為不管問題的規模有多大,都能一下子得到答案。。。然后看看 O(n),小明的問題就是這個復雜度的,如果問題規模是n,需要運行n次,顯然已經不錯了,挺快的了。。。但是還有一個更快的,O(log n)的,如果n=1000000 那么才只需要運行 20次不到就能得到答案,但是 O(n)的卻需要運行1000000次,你說哪個快。


?

舉個栗子:

  要求輸入一個n,然后算 1^2+2^2+3^2+4^2+...+n^2的值。

  那么先說一種做法,直接for循環,代碼如下:

#include <iostream>using namespace std;int main() {int n;int sum=0;cin>>n;for(int i=1;i<=n;++i)sum+=i*i;cout<<sum;return 0; }

  顯然這種算法的復雜度是 O (n) 的,因為運行了 n 次嘛。(注意 n 比較大的時候結果會超過 int 的表示范圍,具體看 ACM錄 常識與錯誤那篇文章有說。)

?

  然后看看第二種做法:推出公式來。1^2+2^2+。。。+n^2 = n*(n+1)*(2n+1)/6

  所以第二種做法就是

#include <iostream>using namespace std;int main() {int n;cin>>n;cout<<n*(n+1)*(2*n+1)/6<<endl;return 0; }

  這就是 O ( 1 ) 的復雜度了,那么哪個快就不說了。。。


?

  — 至于后面的 O( n^2 ) ?O( n^3 ) ?O( 2^n ) 啊啥的,也是這樣算,上面那些里面復雜度最高,效率最差的應該是 O(n!),如果 n 是10,就需要運行 3628800 次,這效率,不多說了。。。

  — 上面說的是運行的次數,然后說說時間,對于現在的個人計算機來說,速度大約是一秒能運行10000000(7個0)次多,這個可以自己寫個程序感受一下,for循環10000000次或者更多看看。。。一般來說如果只有加減法 100000000(8個0)次也很快,但是如果有了除法或者其他東西會慢一點。。。

#include <iostream>using namespace std;int main() {int x;for(int i=0;i<1000000000;++i)x=123*321;    // 對比 x=123/321;return 0; }

?

  — 然后對于一個題目來說一般限制了1秒啊2秒啊啥的,那么如果題目的數據規模是100000,那么如果采用的算法是 O(n^2)的,那么就需要運行 10000000000次,也就需要大約1000秒,顯然超時了。。。如果算法是 O(n log n)的,那么大約是 1700000 次還是可以接受的。。。至于 O(n) O(1) O(log n)啥的就更不用說了。。。所以說解一個題目的話要注意數據范圍和時間限制。。。

?

  — 這里順便說下常數吧,之前都是把常數忽略了然后看的是一個大致的增長函數。但是如果常數很大,比如算法只有一個 for 循環,但是里面有1000次運算,那么雖然他的復雜度是 O(n)的,但是對于100000的規模需要運行100000000次,也就很可能會超時了。。。所以當常數比較大的時候要注意看看。。。

  — 至于空間復雜度的話,也就是用的空間的多少和數據規模n的函數,但是因為這個不是很常用而且和時間復雜度幾乎差不多,就不多說了。。。

?

///

?

  — 那么怎么算復雜度呢,在一些算法和數學的書上有十分嚴格的數學方法。。。然而,平時不需要的。。。

  — 其實靠肉眼看看就差不多知道了,看看有幾個循環,大致估算一下運行多少次,然后就知道了。。。這些當寫代碼前想算法的時候其實就已經大致了解了。。。

  — 當然這里對于存在遞歸的算法,就比較麻煩了,這里建議大家學了一些基本的算法之后再來看,因為這里實在是找不到簡單的例子。這里有一個主定理(名字就叫主定理),用來計算遞歸的函數的復雜度計算。比如說一個算法是把問題分成兩個小問題,然后在花費 g(n) 的復雜度來合并兩個小問題得到大問題的解。那么函數差不多是 f(n)=2*f(n/2)+g(n) 至于 f(n) 怎么推,就可以用上面的那個主定理(這里可以去網上找找這個定理學習一下),其實。。。也可以先猜一下,然后帶入那個等式看看行不行。。。

  — 經典的遞推比如 f(n)=2f(n/2)+n 的復雜度就是 O(n log n)。。。所以如果 g(n) 如果比 O(n) 要好的話,顯然最后的復雜度會比 O(n log n)更好。。。

?

  — 另外還有一些復雜度分析比如均攤分析就更喪心病狂了,這種分析是找平均值,期望值啥的,通過概率或者是其他什么東西證明運行比如100次的平均復雜度一定不會高于一個數,所以平均就是多少多少的,這個的話就不詳細多說了,之后學習比較高級的算法的時候才會接觸到。。。(其實是我不會。。。)

?

?

  復雜度分析感覺就這些東西,其實大部分算法的復雜度是一眼就能看出來,當然也有一些需要仔細分析這個算法的各種情況才行。。。

轉載于:https://www.cnblogs.com/whywhy/p/4865609.html

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的算法录 之 复杂度分析。的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。