算法設計與分析--最優二叉搜索樹(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 OptimalBinarySearchTree(q,p,n,e,root,w):
    #n表示內結點個數
    #w[i][j]是內結點bi到bj構成的子樹的存取概率之和,包括兩邊的葉子結點
    #e[i][j]表示搜索代價
    for i in range(n+1):
        w[i+1][i]=q[i]
        e[i+1][i]=0
    for r in range(n):#r:結點個數-1
        for i in range(1,n-r+1):
            j=i+r
            w[i][j]=round(w[i][j-1]+q[j]+p[j],3)
            e[i][j]=round(e[i+1][j]+w[i][j],3)
            root[i][j]=i
            
            #k表示用不同的元素作爲根節點
            for k in range(i+1,j+1):
                t=round(e[i][k-1]+e[k+1][j]+w[i][j],3)
                if t<e[i][j]:
                    e[i][j]=t
                    root[i][j]=k
    print("e")
    for i in range(1,n+2):
        print(e[i][1:])
    print('root')
    for i in range(1,n+2):
        print(root[i][1:])
    print('w')
    for i in range(1,n+2):
        print(w[i])

#葉子結點的存取概率
q=[0.05,0.10,0.05,0.05,0.05,0.10]
#內結點的存取概率
p=[0,0.15,0.10,0.05,0.10,0.20]
n=len(p)-1
e,root,w=[],[],[]
for i in range(n+2):
    e.append([0]*(n+1))
    root.append([0]*(n+1))
    w.append([0]*(n+1))
OptimalBinarySearchTree(q,p,n,e,root,w)

運行結果如圖
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章