<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          “算法復(fù)雜度”——其實并沒有那么復(fù)雜

          共 1226字,需瀏覽 3分鐘

           ·

          2020-07-15 10:11

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

          b26f7719c2f9b339992910b4d54f5e4e.webp


          1、引例:斐波那契數(shù)列(Fibonacci sequence)已知斐波那契數(shù)列:,求它的通項公式。

          a9b22ff22152748be4e8f53615f9bc25.webp

          求解斐波那契數(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(xiàn)(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 + n  for (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 + 15      System.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 + n      System.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 + n      System.out.println("test");    }  }}


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

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

          (1)可以忽略常數(shù)、常系數(shù)和低階項。
          • ()
          • ()
          • ()
          (2)對數(shù)階一般省略底數(shù),統(tǒng)稱 。注:大O表示法僅僅只是一種粗略的分析模型,是一種估算。 它能幫我們快速了解一個算法的執(zhí)行效率。

          5、常見的復(fù)雜度5768a2b46ba49c53c3922807901e42f9.webp其中:
          • 當(dāng)數(shù)據(jù)規(guī)模較小時, 各復(fù)雜度對應(yīng)的曲線如下圖所示。0d766f25f9ebf2bf0faf74f58c680604.webp
          • 當(dāng)數(shù)據(jù)規(guī)模較大時, 各復(fù)雜度對應(yīng)的曲線如下圖所示。ff6f0d60997aaff262e13bf25bb5d5c1.webp
          所以,當(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)用過程如下圖所示。

          4192cabcddf68773a84b12e53b4616f6.webp

          所以,該函數(shù)被遞歸調(diào)用的次數(shù) 二叉樹的節(jié)點數(shù)。即:。因此,該算法的復(fù)雜度為。注: 細(xì)心的同學(xué)可能會發(fā)現(xiàn),當(dāng)時,函數(shù)被遞歸調(diào)用的次數(shù)并不完全等于。這里需要說明的是:復(fù)雜度是一種估算,我們關(guān)心的不是具體的數(shù)值,而是量級和趨勢。 所以,呈指數(shù)級增長的趨勢是毋庸置疑的。

          90056a5bc4e32552791e9d826295d6a6.webp

          (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)過程中穿插講解。

          有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

          歡迎大家關(guān)注Java之道公眾號


          好文章,我在看??

          瀏覽 55
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  超碰夫妻自拍 | 午夜成人无码免费视频 | 爱爱网免费视频 | 大香蕉伊人在线手机网 | 黄片豆花视频 |