評估算法及算法的時間複雜度

2020-12-15 米粒教育

文章導讀

【對於一個給定的算法,通常要評估其正確性和運行效率的高低。算法的正確性評估不在本文範圍之內,本文主要討論從算法的時間複雜度特性去評估算法的優劣。】

程序是用來解決問題的,是由多個步驟或過程組成的,這些步驟和過程就是解決問題的算法。解決一個問題有多種方法,也就有多種算法。每一種算法都可以達到解決問題的目的,但花費的成本和時間不盡相同,從節約成本和時間的角度考慮,需要找出最優算法。那麼,如何衡量一個算法的好壞呢?

顯然,選用的算法應該是正確的(算法的正確性不在此論述)。除此之外,通常有三個方面的考慮:

(1)算法在執行過程中所消耗的時間;

(2)算法在執行過程中所佔資源的大小,例如,佔用內存空間的大小;

(3)算法的易理解性、易實現性和易驗證性等等。

衡量一個算法的好壞,可以通過前面提出的三個方面進行綜合評估。從多個候選算法中找出運行時間短、資源佔用少、易理解、易實現的算法。然而,現實情況卻不盡人意。往往是,一個看起來很簡便的算法,其運行時間要比一個形式上複雜的算法慢的多;而一個運行時間較短的算法往往佔用較多的資源。

因此,在不同情況下需要選擇不同的算法。在實時系統中,對系統響應時間要求高,則儘量選用執行時間少的算法;當數據處理量大,而存儲空間較少時,則儘量選用節省空間的算法。本文主要討論算法的時間特性,並給出算法在時間複雜度上的度量指標。

一個算法在執行過程中所消耗的時間取決於下面的因素:

(1)算法所需數據輸入的時間;

(2)算法編譯為可執行程序的時間;

(3)計算機執行每條指令所需的時間;

(4)算法語句重複執行的次數。

其中(1)依賴於輸入設備的性能,若是脫機輸入,則輸入數據的時間可以忽略不計。(2)(3)取決於計算機本身執行的速度和編譯程序的性能。因此,習慣上將算法語句重複執行的次數作為算法的時間量度。

例如:

add函數僅包含一條語句,執行次數為1次;madd函數包含n次的單重for循環,每次循環都執行x=x+1語句,因此執行次數為n次;loopadd函數包含n次的雙重循環,在第二層循環執行x=x+1語句,因此執行次數為n*n次,即n^2次。

上面的例子並沒有把循環本身執行的次數算進去,下面給出2個執行次數計算較為精確的例子。

上面的程序段執行次數為2n+3次。

再看下面矩陣相加的例子。

矩陣相加的執行次數為2n^2+2n+2。

一般情況下,n為問題規模(大小)的量度,如數組的長度、矩陣的階、圖中的頂點數等等。

對於前面add函數來說,問題規模量度為常數(1);對於數組排序問題來說,問題規模量度為輸入數組的長度(記為n);對於n階矩陣相加來說,問題規模量度為矩陣階數的平方(記為n^2)。

為了給出算法通用的時間量度,用數學概念來描述算法的執行次數,可以把一個算法中語句的執行次數稱為語句頻度或時間頻度,記為T(n)。當問題規模n不斷變化時,時間頻度T(n)也會不斷變化,我們需要評估當n不斷變化時,時間頻度T(n)的變化規律。

若有某個輔助函數f(n),當n趨向於無窮大時,如果T(n)/ f(n)的極限為不等於零的常數,則認為T(n)與f(n)是同量級的函數,記作:T(n) =O(f(n)),O(f(n))稱為算法的漸進時間複雜度,簡稱時間複雜度。

漸進時間複雜度表示的意義是:

(1)在較複雜的算法中,進行精確分析是非常複雜的;

(2)一般來說,我們並不關心T(n)的精確度量,而只是關心其量級。

T (n) = O(f (n)) 表示存在一個常數C,當n趨於正無窮大時,總有T (n) ≤ C * f(n),其意義是T(n)在n趨於正無窮大時跟f(n)基本接近,因此完全可以用f(n)來表示T(n)。

O(f (n))通常取執行次數中最高次方或最大指數部分的項。例如:

(1)陣列元素相加為2n+3 = O(n)

(2)矩陣相加為2n^2+2n+1 = O(n^2)

(3)矩陣相乘為2n^3+4n^2+2n+2 = O(n^3)

在各種不同的算法中,若算法語句的執行次數為常數,則算法的時間複雜度為O(1),按數量級遞增排列,常見的時間複雜度量有:

(1)O(1):常量階,運行時間為常量

(2)O(logn):對數階,如二分搜索算法

(3)O(n):線性階,如n個數內找最大值

(4)O(nlogn):對數階,如快速排序算法

(5)O(n^2):平方階,如選擇排序,冒泡排序

(6)O(n^3):立方階,如兩個n階矩陣的乘法運算

(7)O(2^n):指數階,如n個元素集合的所有子集的算法

(8)O(n!):階乘階,如n個元素全部排列的算法

下圖給出了隨著n的變化,不同量級的時間複雜度變化曲線。

圖1 時間複雜度變化曲線圖

評估算法時間複雜度的具體步驟是:

(1)找出算法中重複執行次數最多的語句的頻度來估算算法的時間複雜度;

(2)保留算法的最高次冪,忽略所有低次冪和高次冪的係數;

(3)將算法執行次數的數量級放入大Ο記號中。

例如,下列三個簡單的程序段:

在程序段(a)中,語句x=x+1不在任何一個循環體內,則它的時間頻度為1,其執行時間是個常量;而(b)中,同一語句被重複執行n次,其時間頻度為n;顯然在(c)中,該語句的頻度為n^2。由此,這三個程序段的時間複雜度為O(1)、O(n)、O(n^2)。分別為常量、線性階和平方階。

對於較為複雜的算法,可以將它們分割成容易估算的幾個部分,然後利用O的求和原則得到整個算法的時間複雜度。例如,若算法的兩個部分的時間複雜度分別為T1(n)=O(f(n))和T2(n)=O(g(n)),則總的時間複雜度為:

T(n)= T1(n)+ T2(n)=O(max(f(n), g(n)))

然而,很多算法的運行時間不僅依賴於問題的規模,也與處理的數據集有關。例如,有的排序算法對某些原始數據(如自小至大有序),則其時間複雜度為O(n),而對另一些數據可達O(n^2)。因此,在估算算法的時間複雜度時,均以數據集中最壞的情況來估算。

文章小結

評估算法時間複雜度的要點是:如果一個算法的執行次數是 T(n),那麼只保留最高次項,同時忽略最高項的係數後得到函數 f(n),此時算法的時間複雜度就是 O(f(n))。

相關焦點

  • 算法的時間複雜度
    算法的時間與空間複雜度事後分析法缺點:不同的數據規模,不同的機器下算法運行的時間不同,無法做到計算運行時間事前分析法大O時間複雜度漸進時間複雜度 隨著n的增長,程序運行時間跟隨n變化的趨勢幾個原則去掉常數項2(n^2) =n^2一段代碼取時間複雜度最高的test(n) { //時間複雜度n^3 for(int i = 0; i < n ; i++){ for(int i = 0; i
  • 算法的時間複雜度和空間複雜度-總結
    第一是從數學上證明算法的正確性,這一步主要用到形式化證明的方法及相關推理模式,如循環不變式、數學歸納法等。而在證明算法是正確的基礎上,第二部就是分析算法的時間複雜度。算法的時間複雜度反映了程序執行時間隨輸入規模增長而增長的量級,在很大程度上能很好反映出算法的優劣與否。因此,作為程式設計師,掌握基本的算法時間複雜度分析方法是很有必要的。
  • 從經典算法題看時間複雜度
    算法的時間複雜度(Time complexity)是一個函數,用於定性描述算法的運行時間。提出時間複雜度的目的是:分析與比較完成同一個任務而設計的不同算法。分析算法的結果意味著算法需要的資源,雖然有時我們關心像內存,通信帶寬或者計算機硬體這類資源,但是通常我們想要度量的是計算時間。
  • 時間複雜度的分析及排序算法總結
    算法時間複雜度是一個函數,它定性描述該算法的運行時間(也就是所花費時間的消耗)。排序算法中各個算法時間複雜度為:O(n2), O(nlogn), O(n)。這些我們之前都學習過,可以先從排序算法來理解時間複雜度。
  • 算法的時間複雜度到底如何計算
    我們把 算法需要執行的運算次數 用 輸入大小n 的函數 表示,即 T(n) 。此時為了 估算算法需要的運行時間 和 簡化算法分析,我們引入時間複雜度的概念。定義:存在常數 c 和函數 f(N),使得當 N >= c 時 T(N) <= f(N),表示為 T(n) = O(f(n)) 。
  • 通過一道面試題目,講一講遞歸算法的時間複雜度!
    ,修煉編程內功)來源:代碼隨想錄相信很多同學對遞歸算法的時間複雜度都很模糊,那麼這篇來給大家通透的講一講。每次n-1,遞歸了n次時間複雜度是O(n),每次進行了一個乘法操作,乘法操作的時間複雜度一個常數項O(1),所以這份代碼的時間複雜度是 n * 1 = O(n)。這個時間複雜度就沒有達到面試官的預期。
  • Python編程之算法複雜度簡介
    在智慧型手機上,用戶會關係啟動一個應用程式需要多長時間,而生物學家則關心系統進化推理計算會持續多久。編寫高效程序並不容易,最簡單直接的方法一般都不是最有效率的。有效的算法一般都會使用一些巧妙的小技巧,這就使得它們非常難以理解。結果經常就是,程式設計師努力地減少了計算複雜度,但是卻增加了概念複雜度。
  • 報導 | 複雜度O(n log n)?整數乘法新算法!
    程序設計競賽的選手們對於如何進行大數乘法計算想必也不陌生——這個利用快速傅立葉變換的Schönhage–Strassen算法早在上個世紀就已經被發明。如今,David Harvey和Joris van der Hoeven宣稱他們發現了複雜度更低的整數乘法算法。
  • 用機器學習構建O(N)複雜度的排序算法,可在GPU和TPU上加速計算
    排序一直是計算機科學中最為基礎的算法之一,從簡單的冒泡排序到高效的桶排序,我們已經開發了非常多的優秀方法。但隨著機器學習的興起與大數據的應用,簡單的排序方法要求在大規模場景中有更高的穩定性與效率。中國科技大學和蘭州大學等研究者提出了一種基於機器學習的排序算法,它能實現 O(N) 的時間複雜度,且可以在 GPU 和 TPU 上高效地實現並行計算。
  • 詳解JAVA數據結構與算法:排序算法
    2) 事前估 算的方 法 通過分析某個算法的 時間複雜度 來判斷哪個算法更優 .時間頻度時間頻度:一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。
  • 圖的最短路徑算法-Floyd算法-弗洛伊德算法
    Floyd算法又稱為插點法,是一種利用動態規劃的思想尋找給定的加權圖中多源點之間最短路徑的算法 在計算機科學中,Floyd-Warshall算法是一種在具有正或負邊緣權重(但沒有負周期)的加權圖中找到最短路徑的算法。算法的單個執行將找到所有頂點對之間的最短路徑的長度(加權)。
  • 算法|NP-hard可能沒那麼難.?
    為了解決這個問題,就有了算法的時間複雜度這一定義。例如:在一個有序數組中使用順序查找一個數字,就需要遍歷整個數組,那麼這個算法的複雜度為。使用時間複雜度,很好的規範了算法的時間長短,但是,內存資源也是算法要考慮的內容。在少量數據時,可能不需要考慮內存消耗,但是在大量數據時,就不得不考慮。例如:對1億數據進行排序的問題,我用Java的Int值讀取1億數據就需要消耗約4G的內存(Python可能需要28G到32G不等)。因此,電腦內存不夠咋辦?
  • 通過 JavaScript 學習算法複雜度
    // 每日前端夜話 第474篇// 正文共:1700 字// 預計閱讀時間:10 分鐘在本文中,我們將探討 「二次方」 和 「n log(n)」 等術語在算法中的含義。我還會用到 JavaScript 中方便的  performance API 來衡量執行時間的差異。
  • 算法圖解 | 分而治之與快速排序算法
    圖片來自極客學院快速排序代碼:算法複雜度看一下其他的算法的複雜度這個示例展示的是最糟情況,在最糟情況下,棧長為O(n),在調用棧的每層都涉及O(n)個元素,完成每層所需的時間都為O(n)。因此整個算法需要的時間為O(n) * O(n) = O(n^2)。
  • 算法基礎入門概述
    T(n)=2,按照推導大O階方法,時間複雜度為O(1).算法的分析也是類似,我們查找一個有n個隨機數字數組中的某個數字,最好的情況是第一個數字就是,那麼算法的時間複雜度為O(1),但也有可能這個數字就在最後一個位置上待著,那麼算法的時間複雜度就是O(n),這是最壞的一種情況了。最壞情況運行時間是一種保證,那就是運行時間將不會再壞了。
  • 前端學習數據結構與算法系列(一):初識數據結構與算法
    前言作為一個對算法沒有任何認知,非科班出身的前端程式設計師,如果想提高自己的能力,不再只寫業務代碼當一個應用工程師,算法是必須掌握的一門本領。算法也是一種思想,當你去讀一些優秀框架的源碼,如果對算法和數據結構一無所知,讀起來很困難,你無法理解人家為什麼要那樣寫,那樣寫的好處是什麼,接下來就跟大家分享下作為一個前端程式設計師,如何學習數據結構與算法。
  • 折衷算法
    個。因此對這些子集逐個進行判斷和檢測的時間複雜度為折衷算法的基本思路是將問題分成兩部分,分別單獨解決它們,然後合併,找出最後的解。將問題分成兩部分後,問題的規模比原來小,並使複雜度上得到簡化,因而有可能解決問題。我們使用折衷算法來解決上面的問題。下面是算法的描述:1)將原來的整數集合拆分為2個子集,例如A和B,A中包含前[n / 2]個整數,B中包括剩下的整數。
  • 算法基礎知識 目錄
    ,時間 & 空間複雜度介紹算法和數據結構,而時間,空間複雜度,是算法面試中必考的問題,一旦打錯必掛,所以必須要打好基礎。2-1 算法和數據結構算法特性,數據結構特性,Java 框架基本接口和實現2-2 時間複雜度最好/最壞/平均 時間複雜度,Leetcode 中的時間複雜度2-3 空間複雜度常見空間複雜度,三種空間複雜度第三章
  • 時間複雜度的表示、分析、計算方法……一文帶你看懂時間複雜度!
    名詞解釋:在計算機科學中,時間複雜性,又稱時間複雜度,算法的時間複雜度是一個函數,它定性描述該算法的運行時間。這是一個代表算法輸入值的字符串的長度的函數。時間複雜度常用大O符號表述,不包括這個函數的低階項和首項係數。
  • ​隨機算法(randomized algorithm)概述——概念、方法、類型、複雜度、設計方法和計算舉例(14k字)
    本文概述隨機算法(randomized algorithm)的概念、方法、類型、複雜度、設計方法和計算舉例。關鍵詞:隨機算法(randomized algorithm)、隨機、計算。蒙特卡羅指的是算法的時間複雜度固定,然而結果有一定機率失敗。3.1 隨機化算法(randomizedalgorithm)的四種類型1、數值概率算法:用於數值問題的求解。