原文:https://ethsonliu.com/2018/04...html
算法複雜度的表示一般用三種漸進符號:$O, Ω, Θ$。咱們平時常見的都是第一個,後面兩個多見於教科書。下面先介紹下這三種符號的含義和性質。算法
$O$,讀做「大 O」,非正式來講,$O(g(n))$ 是增加次數小於等於 $g(n)$ 及其常數倍($n$ 趨向於無窮大)的函數集合。函數
教科書上的定義:若是函數 $f(n)$ 包含在 $O(g(n))$ 中,記做 $f(n)∈O(g(n))$(平時使用爲了方便書寫,咱們一般使用 $f(n)=O(g(n))$ 代替)。它的成立條件是:對於全部足夠大的 $n$,$f(n)$ 的上界由 $g(n)$ 的常數倍所肯定,也就是說,存在大於 $0$ 的常數 $c$ 和非負整數 $n_0$,使得對於全部的 $n≥n_0$ 來講,$f(n)≤c⋅g(n)$。spa
下圖說明了這個定義:設計
下面給出幾個例子:htm
$$ \begin{align} n&=O(n^2)\\ 100n+5&=O(n^2)\\ \frac 12n(n-1)&=O(n^2)\\ n^3&≠O(n^2)\\ 0.00001n^3&≠O(n^2) \end{align} $$blog
$Ω$,讀做「omega」,$Ω(g(n))$ 是增加次數大於等於 $g(n)$ 及其常數倍($n$ 趨向於無窮大)的函數集合。遞歸
教科書上的定義:若是函數 $f(n)$ 包含在 $Ω(g(n))$中,記做 $f(n)=Ω(g(n))$。它的成立條件是:對於全部足夠大的 $n$,$f(n)$ 的下界由 $g(n)$ 的常數倍所肯定,也就是說,存在大於 $0$ 的常數 $c$ 和非負整數 $n_0$,使得對於全部的 $n≥n_0$ 來講,$f(n)≥c⋅g(n)$。 ip
下圖說明了這個定義:rem
下面給出幾個例子:
$$ \begin{align} n^3&=Ω(n^2)\\ \frac 12n(n-1)&=Ω(n^2)\\ 100n+5&≠Ω(n^2) \end{align} $$
讀做「theta」。
教科書上的定義:若是函數 $f(n)$ 包含在 $Θ(g(n))$ 中,記做 $f(n)=Θ(g(n))$。它的成立條件是:對於全部足夠大的 $n$,$f(n)$ 的上界和下界由 $g(n)$ 的常數倍所肯定,也就是說,存在大於 $0$ 的常數 $c_1, c_2$ 和非負整數 $n_0$,使得對於全部的 $n≥n_0$ 來講,$c_1⋅g(n)≤f(n)≤c_2⋅g(n)$。
下圖說明了這個定義:
下面給出幾個例子:
$$ \begin{align} \frac 12n(n-1)&=Θ(n^2)\tag{$c_1=\frac 14,c_2=\frac 12,n_0=2$}\\ 6n^3&≠Θ(n^2) \end{align} $$
性質 若是 $t_1(n)=O(g_1(n))$ 而且 $t_2(n)=O(g_2(n))$,則
$$ t_1(n)+t_2(n)=O(\max\{g_1(n),g_2(n)\}) $$
上面的公式對於 $Ω$ 和 $Θ$ 符號,一樣成立。
證實 增加次數的證實是基於如下簡單事實:對於 $4$ 個任意實數 $a_1,b_1,a_2,b_2$,若是 $a_1≤b_1$ 而且 $a_2≤b_2$,則 $a_1+a_2≤2\max\{b_1,b_2\}$。
由於 $t_1(n)=O(g_1(n))$,且存在正常量 $c_1$ 和非負整數 $n_1$,使得對於全部的 $n≥n_1$,有 $t_1(n)≤c_1g_1(n)$。同理,由於 $t_2(n)=O(g_2(n))$,對於全部的 $n≥n_2$,亦有 $t_2(n)≤c_2g_2(n)$。
假設 $c_3=\max\{c_1,c_2\}$ 而且 $n≥\max\{n_1,n_2\}$,就能夠利用兩個不等式的結論將其相加,得出如下結論:
$$ \begin{align} t_1(n)+t_2(n)&≤c_1g_1(n)+c_2g_2(n)\\ &≤c_3g_1(n)+c_3g_2(n)=c_3[g_1(n)+g_2(n)]\\ &≤c_3⋅2\max\{g_1(n),g_2(n)\} \end{align} $$
也就是說,對於兩個連續執行部分組成的算法,它的總體效率是由具備較大增加次數的部分所決定的,即效率較差的部分決定。
對於一個普通函數(即非遞歸函數),其時間複雜度天然易求。下面咱們主要談談如何求解遞歸函數的時間複雜度。
遞歸函數一般會有如下的方程式:
$$ T(n)=aT(\frac nb)+f(n)\tag{2.1} $$
其中,$a≥1,b>1$,且都是常數,$f(n)$ 是漸近正函數。遞歸式 $(2.1)$ 描述的是這樣一種算法的運行時間:它將規模爲 $n$ 的問題分解爲 $a$ 個子問題,每一個子問題規模爲 $\frac nb$,其中 $a≥1,b>1$。$a$ 個子問題遞歸地求解,每一個花費時間 $T(\frac nb)$。函數 $f(n)$ 包含了問題分解和子問題解合併的代價。
解決上述方程式經常使用的方法有兩種:主定理 和 分治法。
令 $a≥1,b>1$,且都是常數,$f(n)$ 是一個函數,$T(n)$ 是定義在非負整數上的遞歸式,即:
$$ T(n)=aT(\frac nb)+f(n) $$
其中咱們將 $\frac nb$ 解釋爲 $⌊\frac nb⌋$ 或 $⌈\frac nb⌉$。那麼 $T(n)$ 有以下漸近界:
(Case 1)若是 $f(n)=O(n^c)$,其中 $c<log_ba$,則:
$$ T(n)=Θ(n^{log_ba}) $$
(Case 2)若是存在常數 $k≥0$,使 $f(n)=Θ(n^clog^{k}n)$,其中 $c=log_ba$,則:
$$ T(n)=Θ(n^clog^{k+1}n) $$
(Case 3)若是 $f(n)=Ω(n^c)$,其中 $c>log_ba$,而且對某個常數 $k<1$ 和全部足夠大的 $n$ 有 $af(\frac nb)≤kf(n)$,則:
$$ T(n)=Θ(f(n)) $$
算法導論已有關於這個定理的證實,篇幅較長,故此處省略,有興趣的讀者能夠本身去翻閱下。
分治法先把給定的實例劃分爲若干個較小的實例,對每一個實例遞歸求解,而後若是有必要,再把較小實例的解合併成給定實例的一個解。假設全部較小實例的規模都爲 $\frac nb$,其中 $a$ 個實例須要實際求解,對於 $n=b^k,k=1,2,3...$,其中 $a≥1,b>1$,獲得如下結果:
$$ \begin{align} T(n)&=aT(\frac nb)+f(n)\tag{($2.1$) 遞歸方程式}\\ T(b^k)&=aT(b^{k-1})+f(b^k)\\\ &=a[aT(b^{k-2})+f(b^{k-1})]+f(b^k)=a^2T(b^{k-2})+af(b^{k-1})+f(b^k)\\ &=a^3T(b^{k-3})+a^2f(b^{k-2})+af(b^{k-1})+f(b^k)\\ &=...\\ &=a^kT(1)+a^{k-1}f(b^1)+a^{k-2}f(b^2)+...+a^0f(b^k)\\ &=a^k[T(1)+\sum_{j=1}^{k} {\frac {f(b^j)}{a^j}}]\tag{2.2.7} \end{align} $$
因爲 $a^k=a^{log_bn}=n^{log_ba}$,當 $n=b^k$ 時,對於式 $(2.2.7)$ 咱們能夠推出下式:
$$ T(n)=n^{log_ba}[T(1)+\sum_{j=1}^{log_bn}{\frac {f(b^j)}{a^j}}]\tag{2.2.8} $$
顯然,$T(n)$ 的增加次數取決於常數 $a$ 和 $b$ 的值以及函數 $f(n)$ 的增加次數。
如下是經常使用的的兩條定理,它們依舊創建在遞歸方程式中,即:
$$ T(n)=aT(\frac nb)+f(n)\tag{$a≥1,b>1$} $$
根據以上的方程式有如下兩個定理:
定理 1 對於 $(2.1)$ 遞歸方程式,若 $a=1,b>1,f(n)=c,c$ 爲某個常數,即:
$$ T(n)=T(\frac nb)+c $$
則:
$$ T(n)=Θ(logn) $$
證實 應用主定理 Case 2,其中 $c=log_ba=log_b1=0$,再使 $k=0$,則 $f(n)=Θ(n^clog^kn)=Θ(1)$,這裏的 $f(n)$ 即等於常數 $c$,證實成立。
定理 2 對於 $(2.1)$ 遞歸方程式,若 $a=1,b>1,f(n)=kn+p$,其中 $k>0,p>0$ 且爲某個常數(也就是 $f(n)$ 是一個線性直線方程),即:
$$ T(n)=T(\frac nb)+(kn+p)\tag{$b>1,k>0,p$ 爲某個常數} $$
則:
$$ T(n)=Θ(n) $$
證實 應用分治法中 $(2.2.8)$:
$$ \begin{align} T(n)&=n^{log_ba}[T(1)+\sum_{j=1}^{log_bn}{\frac {f(b^j)}{a^j}}]\\ &=\sum_{j=1}^{log_bn}{(kb^j+p)}\\ &=plog_bn+\frac {kb}{b-1}(n-1)\tag{$k>0,p>0,b>1$}\\ &<pn+\frac {kb}{b-1}(n-1)\\ &=cn-\frac {kb}{b-1}\tag{$c>0$ 且爲某個常數}\\ &=Θ(n) \end{align} $$
證實成立。