最优二叉查找树(optimal BST)

来源:互联网 发布:摇钱树计划软件 编辑:程序博客网 时间:2024/05/16 10:27
/**    最优二叉查找树:一棵有n个结点的二叉查找树,已知每个结点的查找概率Pi(且∑Pi=1),要使查找操作的平均比较次数最小。(这里讨论的是成功查找,不讨论不成功的查找)动态规划:    c[i][j]表示由结点i~j组成的BST成功查找的最小平均查找次数。    r[i][j]表示由结点i~j构成最优二叉查找树时的树根结点。转换公式:    c[i][j] = Min[i<=k<=j]{c[i,k-1] + c[k+1,j]} + Sum{Pi...Pj};时间复杂度是O(n^3)优化:把原来的树根可能是i->j中的任何一个,优化成r[i,j-1] <= r[i,j] <= r[i+1,j]可以证明优化后的时间复杂度是O(n^2)**/const int MAXN = 1000 + 5;double c[MAXN][MAXN];int    r[MAXN][MAXN];double optimalBST(int n, double p[]){    double sum[MAXN] = {0};    for (int i = 1; i <= n; i++)    // 求前i项和是为了简化后面的计算        sum[i] = sum[i-1] + p[i];    if ( fabs(sum[n] - 1.0) > 1e-6 ) // 检验∑Pi=1        return -1.0;    for (int i = 1; i <= n; i++)  // initialize    {        c[i][i-1] = 0;        c[i][i] = p[i];        r[i][i] = i;    }    c[n+1][n] = 0;    for (int d = 1; d < n; d++)    {        for (int i = 1; i <= n-d; i++)        {            int    j = i + d;            int    root = -1;            double minv = 1e9;            for (int k = r[i][j-1]; k <= r[i+1][j]; k++) // k = i -> j 的优化            {                if (minv > c[i][k-1] + c[k+1][j])                {                    minv = c[i][k-1] + c[k+1][j];                    root = k;                }            }            r[i][j] = root;            c[i][j] = minv + sum[j] - sum[i-1];        }    }    return c[1][n];}