1. 程式人生 > >複雜度分析(一)

複雜度分析(一)

  (一) 複雜度分析的由來

     我們平時寫程式碼的時候,想要知道一段程式碼的執行時間,佔用空間等等,一般都是在程式碼開始的記錄一下當前時間,執行結束的時候,再記錄一下時間,最後得出這段程式碼的執行時間,一般就是通過這個來判斷我們的程式碼的執行效率。這種做法沒有錯,但是這樣做統計出來的。

      在我之前寫業務程式碼的時候,比如增刪查改的時候,我經常都是這麼幹的,為了讓一個查詢更快,更有效率,邊除錯,邊分析,找出慢的步驟,再逐一解決。那麼問題來了,我們還需要學這個演算法的時間複雜度分析嗎?

      對於這個問題,之前我也是很茫然,看到演算法時間複雜度分析的相關內容,我就直接忽略,想著工作中也不會這麼分析。

      那麼,我先解釋一下,上面這種做法有什麼弊端呢(其實上面的做法,真心還行)。 1、我們通過這種程式碼得出來的執行時間是很依靠機器的硬體的,要看你CPU的計算能力,記憶體的大小等等(不是很多時候,都會有這麼一個情況,線下測試很快,線上慢成狗了,因為沒有考慮到CPU的分配情況,記憶體佔用情況)。2、這種統計方法受到資料規模的影響很大,在測試環境,測得再OK,上線之後還是問題很大)。

     基於上面這些問題,IT的大牛們,就想了一下,要不對演算法的時間複雜度來個抽象,不要依賴於機器,硬體等等做法呢。所以他們就提出了一種做法就做O(n),時間複雜度做法。

 (二)什麼是時間複雜度O(n)

      時間複雜度:它並不是表示程式碼的真正執行時間,而是表示程式碼的執行時間隨資料規模增長的變化情況。

      下面來看這個例子。

    int GetSum(int n)
    {
    1       var sum = 0;
    2       for (var i = 0; i < n; i++)
            {
    3             sum += i;
            }
            return sum;
   }

         我們知道每個語句的執行操作,從CPU的角度來看,就是讀資料--運算--寫資料,假設這整個操作需要一個單位的時間。我們假設一行程式碼就是一個單位的執行時間,那麼這段程式碼就是2+2n個單位時間,從這裡可以看出來程式的執行時間是和n成正比的。我們把這個規律總結成為一個公式,就是我們的時間複雜度。

    (三)時間複雜度的分析方法

          1、關注執行次數最多的那段程式碼,那個就是這整段程式碼的時間複雜度

          2、乘法法則,兩個時間複雜度相乘,就是整個時間複雜度。(巢狀內外程式碼的複雜度等於內外複雜度的乘積)

          3、總的複雜度等於最大的那個複雜度。(一般兩個複雜度,不是同一個層級的時候,才取最大的,比如o(n)和o(n2),則取o(n2),如果一個是o(n),另外一個是o(m),則時間複雜度就是o(m+n))

      (四)總結

           感覺這個時間複雜度分析,就像設計模式,你說按照設計模式寫出來的程式碼,也不一定是最好的。我們時間複雜度也是一樣,也不一定說o(n)就比o(n2)的好,但是隻要當我們一提到某某某設計模式的時候,心裡馬上就可以勾勒出這個設計模式的程式碼組成結構。當我們一說o(n)的時候,也可以知道這段程式碼是如何組織的。

          還有很多常見的時間複雜度,比如o(1),o(n) o(logn) o(nlogn),o(n2)。下面說說我覺得最難分析的o(logn)這個時間複雜度把。

  int GetSum(int n)
  {
            var i = 1;
            while (i<=n)
            {
                i = i*2;
            }
            return i;
  }

        上面這個例子,一步步來分析,i=2,I=4,i=8,i=16,一直到i<=n。  那這個程式碼執行了多次呢。就是2的x次方小於等於n。 現在要求這個x是多少呢,那就用到我們的對數了x=log2為底,n為真數的對數了。

     int GetSum(int n)
        {
            var i = 1;
            while (i<=n)
            {
                i = i*3;
            }
            return i;
        }

        這個例子也是和上面是一樣的,它是Log3為底,n為真數的對數。

        我們知道對數是可以相互轉化的了 。對數都是可以相互轉化的,我們同時把他們轉化為以十為底的對數,然後去掉常量,就得到了o(logn)。然後o(nlogn)就是n個o(logn)相乘。