1. 程式人生 > >演算法導論程式39--最優二叉搜尋樹(Python)

演算法導論程式39--最優二叉搜尋樹(Python)

最優二叉搜尋樹:

給定一個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  
>>>