演算法複雜度的分析 遞迴分治法

2021-08-08 10:55:39 字數 4266 閱讀 8729

f(n) = o(g(n)):∃c>0,n0∈n,∀n≥n0,f(n)≤cg(n)∃c>0,n0∈n,∀n≥n0,f(n)≤cg(n) ;f的階不高於g的階。

f(n) = ω(g(n)):∃c>0,n0∈n,∀n≥n0,f(n)≥cg(n)∃c>0,n0∈n,∀n≥n0,f(n)≥cg(n) ;f的階不低於g的階。

f(n) = θ(g(n)):⟺f(n)=o(g(n))&&f(n)=ω(g(n))⟺f(n)=o(g(n))&&f(n)=ω(g(n)) ;f的階等於g的階。

f(n) = o(g(n)):∀ε>0,∃n0∈n,∀n≥n0,f(n)/g(n)<ε∀ε>0,∃n0∈n,∀n≥n0,f(n)/g(n)<ε ;f的階低於g的階。

可見,記號o給出了函式f(n)在漸進意義下的上界(但不一定是最小的),相反,記號ω給出的是下界(不一定是最大的)。如果上界與下界相同,表示f(n)和g(n)在漸進意義下是同階的(θ),亦即複雜度一樣。

t(n)=at(n/b)+f(n)型方程;   a>=1;b>0常數;f(n)正整數;
(1):提供乙個簡便的方法(但是我並沒有怎麼理解,老師給的)

比較f(n)和n的log以b為底a的對數次冪大小;

若f(n)小,t(n)=n的log以b為底a的對數次冪;

若f(n)大,t(n)=f(n);

若相等;t(n)=n的log以b為底a的對數次冪乘以log以2為底n的對數。

(2)平時設計或者閱讀乙個演算法的時候,必然會提到演算法的複雜度(包括時間複雜度和空間複雜度)。比如我們說乙個二分查詢演算法的平均時間複雜度為o(log n),快速排序可能是o(n log n)。那這裡的o是什麼意思?這樣的表達是否準確呢?

先插一句,在演算法複雜度分析中,log通常表示以2為底的對數。

演算法複雜度(演算法複雜性)是用來衡量演算法執行所需要的計算機資源(時間、空間)的量。通常我們利用漸進性態來描述演算法的複雜度。

用n表示問題的規模,t(n)表示某個給定演算法的複雜度。所謂漸進性態就是令n→∞時,t(n)中增長最快的那部分。嚴格的定義是:如果存在t˜(n)t~(n) ,當n→∞時,有

t(n)−t˜(n)t(n)→0t(n)−t~(n)t(n)→0

就說t˜(n)t~(n) 是t(n)當n→∞時的漸進性態。

比如t(n) = 2 * n ^ 2 + n log n + 3,那麼顯然它的漸進性態是 2 * n ^ 2,因為當n→∞時,後兩項的增長速度要慢的多,可以忽略掉。引入漸進性態是為了簡化演算法複雜度的表示式,只考慮其中的主要因素。當比較兩個演算法複雜度的時候,如果他們的漸進複雜度的階不相同,那只需要比較彼此的階(忽略常數係數)就可以了。

總之,分析演算法複雜度的時候,並不用嚴格演算出乙個具體的公式,而是只需要分析當問題規模充分大的時候,複雜度在漸進意義下的階。記號o、ω、θ和o可以幫助我們了解函式漸高階的大小。

假設有兩個函式f(n)和g(n),都是定義在正整數集上的正函式。上述四個記號的含義分別是:

f(n) = o(g(n)):∃c>0,n0∈n,∀n≥n0,f(n)≤cg(n)∃c>0,n0∈n,∀n≥n0,f(n)≤cg(n) ;f的階不高於g的階。

f(n) = ω(g(n)):∃c>0,n0∈n,∀n≥n0,f(n)≥cg(n)∃c>0,n0∈n,∀n≥n0,f(n)≥cg(n) ;f的階不低於g的階。

f(n) = θ(g(n)):⟺f(n)=o(g(n))&&f(n)=ω(g(n))⟺f(n)=o(g(n))&&f(n)=ω(g(n)) ;f的階等於g的階。

f(n) = o(g(n)):∀ε>0,∃n0∈n,∀n≥n0,f(n)/g(n)<ε∀ε>0,∃n0∈n,∀n≥n0,f(n)/g(n)<ε ;f的階低於g的階。

可見,記號o給出了函式f(n)在漸進意義下的上界(但不一定是最小的),相反,記號ω給出的是下界(不一定是最大的)。如果上界與下界相同,表示f(n)和g(n)在漸進意義下是同階的(θ),亦即複雜度一樣。

列舉一些常見的函式之間的漸高階的關係:

logn!=θ(nlogn)log⁡n!=θ(nlog⁡n)

logn2=θ(logn)log⁡n2=θ(log⁡n)

logn2=o(n−−√)log⁡n2=o(n)

n=ω(log2n)n=ω(log2⁡n)

log2n=ω(logn)log2⁡n=ω(log⁡n)

2n=ω(n2)2n=ω(n2)

2n=o(3n)2n=o(3n)

n!=o(nn)n!=o(nn)

2n=o(n!)2n=o(n!)

有些人可能會把這幾個記號跟演算法的最壞、最好、平均情況複雜度混淆,它們有區別,也有一定的聯絡。

即使問題的規模相同,隨著輸入資料本身屬性的不同,演算法的處理時間也可能會不同。於是就有了最壞情況、最好情況和平均情況下演算法複雜度的區別。它們從不同的角度反映了演算法的效率,各有用處,也各有侷限。

有時候也可以利用最壞情況、最好情況下演算法複雜度來粗略地估計演算法的效能。比如某個演算法在最壞情況下時間複雜度為θ(n ^ 2),最好情況下為θ(n),那這個演算法的複雜度一定是o(n ^ 2)、ω(n)的。也就是說n ^ 2是該演算法複雜度的上界,n是其下界。

接下來看看master定理。

有些演算法在處理乙個較大規模的問題時,往往會把問題拆分成幾個子問題,對其中的乙個或多個問題遞迴地處理,並在分治之前或之後進行一些預處理、彙總處理。這時候我們可以得到關於這個演算法複雜度的乙個遞推方程,求解此方程便能得到演算法的複雜度。其中很常見的一種遞推方程就是這樣的:

設常數a >= 1,b > 1,f(n)為函式,t(n)為非負整數,t(n) = a t(n / b) + f(n),則有:

若f(n)=o(nlogba−ε),ε>0f(n)=o(nlogb⁡a−ε),ε>0 ,那麼t(n)=θ(nlogba)t(n)=θ(nlogb⁡a) 。

若f(n)=θ(nlogba)f(n)=θ(nlogb⁡a) ,那麼t(n)=θ(nlogbalogn)t(n)=θ(nlogb⁡alog⁡n) 。

若f(n)=ω(nlogba+ε),ε>0f(n)=ω(nlogb⁡a+ε),ε>0 ,並且對於某個常數c < 1和充分大的n有af(n/b)≤cf(n)af(n/b)≤cf(n) ,那麼t(n)=θ(f(n))t(n)=θ(f(n)) 。

比如常見的二分查詢演算法,時間複雜度的遞推方程為t(n) = t(n / 2) + θ(1),顯然有nlogba=n0=θ(1)nlogb⁡a=n0=θ(1) ,滿足master定理第二條,可以得到其時間複雜度為t(n) = θ(log n)。

再看乙個例子,t(n) = 9 t(n / 3) + n,可知nlogba=n2nlogb⁡a=n2 ,令ε取1,顯然滿足master定理第一條,可以得到t(n) = θ(n ^ 2)。

來乙個稍微複雜一點兒例子,t(n) = 3 t(n / 4) + n log n。nlogba=o(n0.793)nlogb⁡a=o(n0.793) ,取ε = 0.2,顯然當c = 3 / 4時,對於充分大的n可以滿足a * f(n / b) = 3 * (n / 4) * log(n / 4) <= (3 / 4) * n * log n = c * f(n),符合master定理第三條,因此求得t(n) = θ(n log n)。

運用master定理的時候,有一點一定要特別注意,就是第一條和第三條中的ε必須大於零。如果無法找到大於零的ε,就不能使用這兩條規則。

舉個例子,t(n) = 2 t(n / 2) + n log n。可知nlogba=n1nlogb⁡a=n1 ,而f(n) = n log n,顯然不滿足master定理第二條。但對於第一條和第三條,也無法找到大於零的ε使得nlogn=o(n1−ε)nlog⁡n=o(n1−ε)或者nlogn=ω(n1+ε)nlog⁡n=ω(n1+ε) ,因此不能用master定理求解,只能尋求別的方式求解。比如可以利用遞迴樹求出該演算法的複雜度為t(n)=o(nlog2n)t(n)=o(nlog2⁡n) 。簡單的說一下計算過程:

遞迴樹的建立過程,就像是模擬演算法的遞推過程。樹根對應的是輸入的規模為n的問題,在遞迴處理子問題之外,還需要n log n的處理時間。然後根據遞推公式給根節點新增子節點,每個子節點對應乙個子問題。這裡需要兩個子節點,每個節點處理規模為n / 2的問題,分別需要(n / 2) * log(n / 2)的時間。因此在第二層一共需要n * (log n - 1)的時間。第三層節點就是將第二層的兩個節點繼續**開,得到四個各需要(n / 4) * log(n / 4)時間的節點,總的時間消耗為n * (log n - 2)。依此類推,第k(設樹根為k = 0)層有2 ^ k的節點,總的時間為n * (log n - k)。而且可以知道,這棵樹總共有log n層(最後一層每個節點只處理規模為1的子問題,無須再分治)。最後將每一層消耗的時間累加起來,得到:

∑k=0lognn(logn−k)=12nlogn(logn+1)=o(nlog2n)

摘自這個**;

演算法時間複雜度 分治與遞迴

演算法時間複雜度之分治與遞迴 演算法是解決問題的辦法或法則,而 速度 就是演算法之魂,在計算機中所謂的 速度 就是 時間 空間。在大家初期的演算法學習中,往往感覺演算法這東西摸不著頭腦,會感覺 它為什麼會這麼用,這種用法究竟有什麼不同,我自己的解法就不好嗎?所以要想解決這種困惑,要想真正的理解演算法...

遞迴演算法時間複雜度分析

一般情況下,演算法中基本操作重複的次數就是問題規模n的某個函式f n 進而分析f n 隨n的變化情況並確定t n 的數量級。這裡用 o 來表示數量級,給出演算法時間複雜度。t n o f n 它表示隨問題規模n的增大,演算法的執行時間增長率和f n 增長率成正比,這稱作演算法的漸進時間複雜度。而我們...

遞迴演算法的時間複雜度分析

在演算法分析中,當乙個演算法中包含遞迴呼叫時,其時間複雜度的分析會轉化為乙個遞迴方程求解。實際上,這個問題是數學上求解漸近階的問題,而遞迴方程的形式多種多樣,其求解方法也是不一而足,比較常用的有以下四種方法 1 代入法 substitution method 代入法的基本步驟是先推測遞迴方程的顯式解...