演算法導論讀書筆記(19)

2021-07-28 08:07:38 字數 4220 閱讀 8697

最優二叉搜尋樹(optimal binary search tree)問題的形式化定義如下:給定乙個由 n 個互異的關鍵字組成的序列 k =

, k2

, … , kn

>,且關鍵字有序(有 k1

< …

),我們要從這些關鍵字中構造一棵二叉查詢樹。對每個關鍵字 ki

,一次搜尋為 ki

的概率是 pi

。某些搜尋的值可能不在 k 內,因此還有 n + 1 個「虛擬鍵」 d0

, d1

, … , dn

代表不在 k 內的值。其中, d0

代表所有小於 k1

的值, dn

代表所有大於 kn

的值,而對於 i = 1, 2, …, n - 1 ,虛擬鍵 di

代表所有位於 ki

和 ki

+1 之間的值。對每個虛擬鍵 di

,一次搜尋對應於 di

的概率是 qi

。下圖是 n = 5個關鍵字的集合上的兩棵二叉查詢樹。

其中各結點的概率如下表所示:

每個關鍵字 ki

是乙個內部結點,每個虛擬鍵 di

是乙個葉子。每次搜尋要麼成功(找到某個關鍵字 ki

),要麼失敗(找到某個虛擬鍵 di

),因此有如下公式:

因為已知了每個關鍵字和每個虛擬鍵被搜尋的概率,因而可以確定在一棵給定的二叉查詢樹 t 內一次搜尋的期望代價。假設一次搜尋的實際代價為檢查的結點個數,即在 t 內搜尋所發現的結點的深度加1.所有在 t 內一次搜尋的期望代價為

其中 deptht

代表樹 t 內乙個結點的深度。

對給定的一組概率,我們的目標是構造乙個期望搜尋代價最小的二叉查詢樹。把這種樹稱為最優二叉查詢樹。下面將使用動態規劃方法來解決這個問題。

為描述一棵最優二叉查詢樹的最優子結構,首先要看它的子樹。一棵二叉查詢樹的任意一棵子樹必定包含在連續範圍內的關鍵字 ki

,…, kj

,有 1 <= i

<=j

<= n 。另外,一棵含有關鍵字 ki

,…, kj

的子樹必定也含有虛擬鍵 di

-1 ,…, dj

作為葉子。

現在我們可以描述最優子結構:如果一棵最優二叉查詢樹 t 有一棵包含關鍵字 ki

,…, kj

的子樹 t』 ,那麼這棵子樹 t『 對於關鍵字 ki

,…, kj

和虛擬鍵di

-1 ,…, dj

的子問題也必定是最優的。

使用最優子結構來說明可以根據子問題的最優解,來構造原問題的乙個最優解。給定關鍵字 ki

,…, kj

,假設 kr

( i<= r

<= j ),將是包含這些鍵的一棵最優子樹的根。根 kr

的左子樹包含關鍵字 ki

,…, kr

-1 (和虛擬鍵 di

-1 ,…, dr

-1 ),右子樹包含關鍵字 kr

+1 ,…, kj

(和虛擬鍵 dr

,…, dj

)。我們只要檢查所有的候選根 kr

,並且確定所有包含關鍵字 ki

,…, kr

-1 和 kr

+1 ,…, kj

的最優二叉查詢樹,就可以保證找到一棵最優的二叉查詢樹。

現在可以遞迴地定義乙個最優解的值了。選取子問題域為找乙個包含關鍵字 ki

,…, kj

的最優二叉查詢樹,其中 i >= 1 , j

<= n 且 j >= i - 1。(當 j >= i - 1時沒有真是的關鍵字,只有虛擬鍵 di

-1 )。定義 e [ i , j ]為搜尋一棵包含關鍵字 ki

,…, kj

的最優二叉查詢樹的期望代價。最終,我們要計算的是 e [ 1 ,n ]。

當 j = i - 1時出現簡單情況。此時只有虛擬鍵 di

-1 。期望的搜尋代價為 e [ i , i - 1 ] = qi

- 1。

當 j >= i 時,需要從 ki

,…, kj

中選擇乙個根 kr

,然後用關鍵字 ki

,…, kr

-1 來構造一棵最優二叉查詢樹作為其左子樹,並用關鍵字 kr

+1 ,…, kj

來構造一棵最優二叉查詢樹作為其右子樹。當一棵樹成為乙個結點的子樹時,子樹中每個結點的深度增加1。這個子樹的期望搜尋代價增加為子樹中所有概率的總和。對一棵有關鍵字 ki

,…, kj

的子樹,定義概率的總和為

因此,如果 kr

是一棵包含關鍵字 ki

,…, kj

的最優子樹的根,則有

e [ i , j ] = pr

+ ( e [ i , r - 1 ] + w ( i , r - 1 )) + ( e [ r + 1 , j ] + w ( r + 1 , j ))

注意w ( i , j ) = w ( i , r - 1 ) + pr

+ w ( r + 1 , j )

可以將 e [ i , j ]重寫為

e [ i , j ] = e [ i , r - 1 ] + e [ r + 1 , j ] + w ( i , j )

假設我們知道該採用哪乙個結點 kr

作為根。我們選擇有最低期望搜尋代價的結點作為根,從而得到最終的遞迴式:

下面的偽碼以概率 p1

,…, pn

和 q1

,…, qn

以及規模為 n 為輸入,返回表 e 和 root 。

optimal-bst(p, q, n)

1 let e[1 .. n + 1, 0 .. n], w[1 .. n + 1, 0 .. n] and root[1 .. n, 1 .. n] be new tables

2 for i = 1 to n + 1

3 e[i, i - 1] = q_i - 1

4 w[i, i - 1] = q_i - 1

5 for l = 1 to n

6 for i = 1 to n - l + 1

7 j = i + l - 1

8 e[i, j] = ∞

9 w[i, j] = w[i, j - 1] + p_j + q_j

10 for r = i to j

11 t = e[i, r - 1] + e[r + 1, j] + w[i, j]

12 if t < e[i, j]

13 e[i, j] = t

14 root[i, j] = r

15 return e and root

此過程的操作比較直觀。第1~4行初始化 e [ i , j - 1 ]和 w [ i , j - 1 ]的值。第5~14行的for迴圈利用上面兩個遞迴式來計算 e [ i , j ]和 w [ i , j ],在第10~14行,嘗試每個下標 r 以確定使用哪個關鍵字 kr

來作為包含關鍵字 ki

,…, kj

的最優二叉查詢樹的根。無論何時發現乙個更好的關鍵字來作為根,這個for迴圈在 root [ i , j ]中儲存下標 r 的當前值。

下圖是根據上面二叉查詢樹的關鍵字分布,程式optimal-bst計算出的表 e [ i , j ]和 w [ i , j ]和 root [ i , j ]。

optimal-bst過程需要 θ ( n3

)。

讀書筆記 演算法導論

第2章演算法入門 浮於表面不如深入其中,送給自己,自己是最大的敵人,那麼就盡最大努力去克服自己,沉思,冷靜,不浮躁!勘誤 在演算法導論第9頁,扼要的扼 內容提要 1 偽 的表示方法 2 插入排序演算法分析 3 迴圈不變式 4 演算法設計之分治法 divide and conquer 5 合併排序演算...

演算法導論 讀書筆記2010 12 6

演算法就是一系列的計算步驟,用來將輸入資料轉換為輸出結果。資料結構師儲存和組織資料的一種方式,以便於對資料進行訪問和修改。插入排序演算法,對n個資料項的時間大約是c1n 2,其中c1是乙個不依賴於n的常量。亦即該演算法所需的時間大致與n 2成正比。合併排序演算法,排序n個資料項的時間大約是c2log...

《演算法導論》讀書筆記(一)

理解 輸入到輸出的計算過程稱為演算法。1.演算法描述 2.證明演算法正確性 3.分析演算法效率 兩個例子 1.插入排序 思想 從未排序的序列中取出乙個元素,將其插入到已排序序列的正確位置。實現 include include using namespace std int main for int ...