演算法導論程式39--最優二叉搜尋樹(Python)
阿新 • • 發佈:2019-02-01
最優二叉搜尋樹:
給定一個n個不同關鍵字的已排序的序列K=<k1,k2,...,kn>(因此k1<k2<...<kn)我們希望用這些關鍵字構造一棵二叉樹。對每個關鍵字ki,都有一個概率pi表示其搜尋頻率。
有些要搜尋的值可能不在K中,因此,我們還有n+1個“偽關鍵字”d0,d1,d2,...,dn表示不在K中的值。d0表示所有小於k1的值,dn表示所有大於kn的值,對i=1,2,...,n-1偽關鍵字di表示所有在ki和k(i+1)之間的值。
對每個偽關鍵字di也都有一個概率qi表示對應的搜尋頻率。
假定一次搜尋的代價等於訪問的結點數,即此次搜尋找到的結點在T中的深度再加1.那麼在T中進行一次搜尋的期望代價為:
對於一個給定的概率集合,我們希望構造一棵期望搜尋代價最小的二叉搜尋樹,我們稱之為最優二叉搜尋樹。
用動態規劃方法求解此問題:
步驟1:最優二叉搜尋樹的結構:
考慮一棵二叉搜尋樹的任意子樹,它必須包含連續關鍵字ki,...,kj(1<=i<=j<=n),而且其葉結點必然是偽關鍵字d(i-1),....,dj。
最優子結構:
如果一棵最優二叉搜尋樹T中有一棵包含關鍵字ki,...,kj(1<=i<=j<=n)的子樹T‘,那麼T'必然是包含關鍵字ki,...,kj和偽關鍵字d(i-1),....,dj的子問題的最優解。
步驟2:一個遞迴演算法
root[i, j]儲存根結點kr的下標r。
步驟3:計算最優二叉搜尋樹的期望搜尋代價
def optimal_bst(p,q,n): e=[[0 for j in range(n+1)]for i in range(n+2)] w=[[0 for j in range(n+1)]for i in range(n+2)] root=[[0 for j in range(n+1)]for i in range(n+1)] for i in range(n+2): e[i][i-1]=q[i-1] w[i][i-1]=q[i-1] for l in range(1,n+1): for i in range(1,n-l+2): j=i+l-1 e[i][j]=float("inf") w[i][j]=w[i][j-1]+p[j]+q[j] for r in range(i,j+1): t=e[i][r-1]+e[r+1][j]+w[i][j] if t<e[i][j]: e[i][j]=t root[i][j]=r return e,root if __name__=="__main__": p=[0,0.15,0.1,0.05,0.1,0.2] q=[0.05,0.1,0.05,0.05,0.05,0.1] e,root=optimal_bst(p,q,5) for i in range(5+2): for j in range(5+1): print(e[i][j]," ",end='') print() for i in range(5+1): for j in range(5+1): print(root[i][j]," ",end='') print()
執行:
>>>
== RESTART: D:\Program Files\Python\test\algorithms\演算法導論\39-optimal-bst.py ==
0 0 0 0 0 0.1
0.05 0.45000000000000007 0.9 1.25 1.75 2.75
0 0.1 0.4 0.7 1.2 2.0
0 0 0.05 0.25 0.6 1.2999999999999998
0 0 0 0.05 0.30000000000000004 0.9
0 0 0 0 0.05 0.5
0 0 0 0 0 0.1
0 0 0 0 0 0
0 1 1 2 2 2
0 0 2 2 2 4
0 0 0 3 4 5
0 0 0 0 4 5
0 0 0 0 0 5
>>>