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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

“算法复杂度”——其实并没有那么复杂

發(fā)布時間:2025/3/21 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 “算法复杂度”——其实并没有那么复杂 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

算法是用于解決特定問題的一系列的執(zhí)行步驟。使用不同算法,解決同一個問題,效率可能相差非常大。為了對算法的好壞進(jìn)行評價,我們引入?“算法復(fù)雜度”?的概念。

?

1、引例:斐波那契數(shù)列(Fibonacci sequence)

已知斐波那契數(shù)列:,求它的通項公式。

求解斐波那契數(shù)列的方法有很多種,這里只介紹兩種:遞歸法和平推法。

package com.atangbiji;public class Main {public static void main(String[] args) {// 輸出通項F(n)System.out.println(fib1(1));System.out.println(fib1(2));System.out.println(fib1(3));System.out.println(fib1(4));System.out.println(fib1(5));System.out.println(fib2(70));}/** 求斐波那契數(shù)列(Fibonacci sequence)* F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)的通項F(n).*//** 方法一:遞歸法* 最高支持 n = 92 ,否則超出 Long.MAX_VALUE* @param n * @return f(n) * */public static long fib1(int n) {if (n < 1 || n > 92)return 0;if (n < 3)return 1;return fib1(n - 1) + fib1(n - 2);}/** 方法二:平推法* 最高支持 n = 92 ,否則超出 Long.MAX_VALUE* @param n * @return f(n) * */public static long fib2(int n) {if (n < 1 || n > 92)return 0;//n: 1 2 3 4 5 ……//F(n): 1 1 2 3 5 ……long first = 1;long second = 1;for (int i = 3; i <= n; i++) {long sum = first + second;first = second;second = sum;}return second;}}

通過測試,我們可以發(fā)現(xiàn):當(dāng)n的取值較大時(如:n = 60),若采用遞推法計算則會發(fā)現(xiàn)遲遲不出結(jié)果,若采用平推法計算則可以秒出結(jié)果。由此可見,?平推法的效率明顯高于遞推法。

?

2、如何評估算法的好壞?

  • 正確性

  • 可讀性

  • 健壯性:對不合理輸入的反應(yīng)能力和處理能力。

  • 時間復(fù)雜度(time complexity):?估算程序指令的執(zhí)行次數(shù)(執(zhí)行時間)。

  • 空間復(fù)雜度(space complexity):?估算所需占用的存儲空間。

注:一般情況下,我們主要考慮算法的時間復(fù)雜度。?(因為目前計算機的內(nèi)存一般都比較大)

?

3、時間復(fù)雜度的估算

我們可以用程序指令的執(zhí)行次數(shù)來估算時間復(fù)雜度。例如:

(1)函數(shù)test1

public static void test1(int n) {//總執(zhí)行次數(shù) = 14// 1(判斷語句可以忽略)if (n > 10) {System.out.println("n > 10");} else if (n > 5) {System.out.println("n > 5");} else {System.out.println("n <= 5");} // 1 + 4 + 4 + 4 for (int i = 0; i < 4; i++) {System.out.println("test"); }}

(2)函數(shù)test2

public?static?void?test2(int?n)?{//總執(zhí)行次數(shù) = 1 + 3n//1 + n + n + nfor (int i = 0; i < n; i++) {System.out.println("test");} }

(3)函數(shù)test3

public static void test3(int n) {//總執(zhí)行次數(shù) = 48n + 1// 1 + 2n + n * (1 + 45)for (int i = 0; i < n; i++) {for (int j = 0; j < 15; j++) {// 1 + 15 + 15 + 15System.out.println("test");} }}

(4)函數(shù)test4

public?static?void?test4(int?n)?{//總執(zhí)行次數(shù) = 3n^2 +3n +1// 1 + 2n + n * (1 + 3n)for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) { // 1 + n + n + nSystem.out.println("test");}} }

(5)★ 函數(shù)test5

public static void test5(int n) {//總執(zhí)行次數(shù) = log2(n)/** n = 2 , 執(zhí)行 1 次* n = 4 , 執(zhí)行 2 次* n = 8 , 執(zhí)行 3 次 * */while ((n = n/2) > 0) { // 倍速減小System.out.println("test"); // 只考慮這一句的執(zhí)行次數(shù)} }

(6)函數(shù)test6

public?static?void?test6(int?n)?{//總執(zhí)行次數(shù) = log5(n)while ((n = n/5) > 0) {System.out.println("test"); // 只考慮這一句的執(zhí)行次數(shù)} }

(7)函數(shù)test7

public?static?void?test7(int?n)?{//總執(zhí)行次數(shù) = 3n*log2(n) + 3log2(n) + 1// 1 + 2 * log2(n) + log2(n) * (1 + 3n)/** n = 2 , 執(zhí)行 1 次* n = 4 , 執(zhí)行 2 次* n = 8 , 執(zhí)行 3 次 * */for (int i = 1; i < n; i += i) { // i = i + i = i * 2(倍速增大)for (int j = 0; j < n; j++) { // 1 + n + n + nSystem.out.println("test");}} }

?

4、大O表示法

為了進(jìn)一步簡化復(fù)雜度的計算,我們一般使用大O表示法來描述時間(或空間)復(fù)雜度。它表示的是?數(shù)據(jù)規(guī)模為n?時算法所對應(yīng)的復(fù)雜度。

大O表示法的性質(zhì):

(1)可以忽略常數(shù)、常系數(shù)和低階項。

  • 9 >> O(1)

  • 2n + 3 >> O(n)

  • 3n^2?+ 2n + 6 >> O(n^2)

(2)對數(shù)階一般省略底數(shù),統(tǒng)稱 log n

  • log2 n = log2 9 * log9 n

注:大O表示法僅僅只是一種粗略的分析模型,是一種估算。?它能幫我們快速了解一個算法的執(zhí)行效率。

?

5、常見的復(fù)雜度

其中:

  • 當(dāng)數(shù)據(jù)規(guī)模較小時,?各復(fù)雜度對應(yīng)的曲線如下圖所示。

    ?

  • 當(dāng)數(shù)據(jù)規(guī)模較大時,?各復(fù)雜度對應(yīng)的曲線如下圖所示。

所以,當(dāng)數(shù)據(jù)規(guī)模比較大時,復(fù)雜度為??我們就很難接受了。

?

6、斐波那契數(shù)算法復(fù)雜度分析

(1)遞歸法

public?static?long?fib1(int?n)?{if (n < 1 || n > 92) return 0; if (n < 3) return 1; return fib1(n - 1) + fib1(n - 2);}

假設(shè)計算時和的值已經(jīng)得到,我們可以發(fā)現(xiàn)該函數(shù)每次執(zhí)行的時間主要取決于求和運算。因此,該算法函數(shù)指令的執(zhí)行次數(shù)等價于該函數(shù)被遞歸調(diào)用次數(shù)。

當(dāng)時,該函數(shù)的調(diào)用過程如下圖所示。

所以,該函數(shù)被遞歸調(diào)用的次數(shù)??二叉樹的節(jié)點數(shù)。

即:。

因此,該算法的復(fù)雜度為。

注:?細(xì)心的同學(xué)可能會發(fā)現(xiàn),當(dāng)時,函數(shù)被遞歸調(diào)用的次數(shù)并不完全等于。

這里需要說明的是:復(fù)雜度是一種估算,我們關(guān)心的不是具體的數(shù)值,而是量級和趨勢。?所以,呈指數(shù)級增長的趨勢是毋庸置疑的。

(2)平推法

public static long fib2(int n) {if (n < 1 || n > 92)return 0;//n: 1 2 3 4 5 ……//F(n): 1 1 2 3 5 ……long first = 1;long second = 1;for (int i = 3; i <= n; i++) {long sum = first + second;first = second;second = sum;}return second; }

顯然,平推法的時間復(fù)雜度為。

?

7、算法的優(yōu)化方向

(1)用盡量少的執(zhí)行步驟(運行時間)。

(2)用盡量少的存儲空間。

(3)根據(jù)情況,空間換時間或者時間換空間。

更多關(guān)于復(fù)雜度的知識,我們會在后續(xù)數(shù)據(jù)結(jié)構(gòu)和算法的設(shè)計與實現(xiàn)過程中穿插講解。

總結(jié)

以上是生活随笔為你收集整理的“算法复杂度”——其实并没有那么复杂的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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