算法设计与分析——最优二分搜索树(动态规划)

最优二分搜索树问题

对于一个给定的序列,{b0,a1,b1……an,bn},其中a1,a2……an是实节点,b0,b1,b2……bn是虚节点(就是二分搜索树最终找不到实节点的范围),如何找出并构建一个总耗费最小的二分搜索树?

问题分析

最优二分搜索树的左、右子树也一定是最优二分搜索树。该问题具有最优子结构且子问题重复性,符合动态规划的特性。
故利用动态规划的思想来解此问题。

1.描述最优解结构

目标:
虚节点{b0, b1…… ,bn}和实节点{ a1,a2 ……an }构成树T1n,找出并构建总耗费最小的二分搜索树。
分析:
虚节点{bi-1, bi…… ,bj}和实节点{ ai,ai+1 ……aj }构成以ak为根的二叉树Tij的查找总耗费最小
左子树Ti,k-1由虚节点{bi-1, bi…… ,bk-1}和实节点{ ai,ai+1 ……ak-1 }构成
右子树Tk+1,j由虚节点{bk, bk+1… ,bj}和实节点{ ak+1, ……aj }构成

2.递归地定义最优值(写出状态转移方程)

T[i][j] 由实节点a1…an 和虚节点 b0…bn构成,ak即为根结点
dp[i][j]:T[i][j]的最优查询总耗费,1<=i<=n+1,0<=j<=n,故dp[ ][ ]的长度为n+2
dp[1][0]为左边虚节点b0的代价…dp[n+1][n]为左边虚节点bn的代价

w[i][j]:子树接在一个节点之下,构成新树T[i][j]所增加的耗费
p[]:查询成功的概率
q[]:查询失败的概率
d[i][j]记录根结点的位置

状态转化公式:
若j=i-1,为空树;即dp[i][i-1]=q[i-1];w[i][i-1]=q[i-1];
dp[i][j]=min{dp[i][k-1]+dp[k+1][j]+w[i][j]} ,i<=k<=j

w[i][j]=w[i][j-1]+p[j]+q[j]

3.以自底向上的递推方式计算出最优值(dp[1][n])

根据计算最优值时得到的信息,以递归方法构造一个最优解(构建最优二叉搜索树)

具体实现:

public class BestBinarySearchTree {
    public static double Optimal_BST( double dp[][],double p[],double q[],int n,int root[][]){

        double w[][]=new double[n+2][n+2];

        //空树的情况:空节点b0对应i=1,空节点bn对应i=n+1
        for(int i=1;i<=n+1;i++){
            dp[i][i-1]=q[i-1];
            w[i][i-1]=q[i-1];
        }

        //l表示共有l个实节点构成的树
        for(int l=1;l<=n;l++){
            for(int i=1;i<=n-l+1;i++){
                int j=l+i-1;
                dp[i][j]=9999;
                w[i][j]=w[i][j-1]+p[j]+q[j];

                for(int k=i;k<=j;k++) {
                    double temp=dp[i][k-1]+dp[k+1][j]+w[i][j];
                    if(tempj)
            return;
        else if(i==j) {
            System.out.println("T" + i + j + "的根为a" + root[i][j]);
            return;
        }
        else {
            System.out.println("T" + i + j + "的根为a" + root[i][j]);
            getBestTree(i, root[i][j]-1, root);
            getBestTree(root[i][j]+1, j, root);
        }
    }

    public static void main(String[] args) {

        double[] p = {0,0.15,0.1,0.05,0.1,0.2};//p[0]无意义,5个实节点
        double[] q= {0.05,0.1,0.05,0.05,0.05,0.1};//6个虚节点

        int len = p.length ;
        int n=len-1;
        double dp[][]=new double[n+2][n+2];
        int root[][]=new int[n+2][n+2];

        System.out.println(Optimal_BST( dp, p , q , n, root));
        getroot( root);
        getBestTree(1,n, root);
    }
}

你可能感兴趣的:(算法设计与分析)