• 动态规划之最优二叉树


    原理来自于《算法导论》,其实和矩阵的动态规划基本一样,所以这里就不作阐述了。

    直接上代码,通过构造了最优的root数组后,很容易再创建一个二叉树(这一小部分大家可以自己理解后试试)。

    关于代码的说明,因为书上给出的是伪代码,数组并没有采用C语言格式,下标不是从0开始,所以算法和root数组我做了调整,让其尊重了C语言数组格式。最后解释最优二叉树时,需要把C语言形式的root数组转换为原来书上的数组格式,简单的做法是下标加1后显示就行了。

    定多个预处理函数

    #define LENGTHP (sizeof(p)/sizeof(p[0]))
    #define LENGTHQ (sizeof(q)/sizeof(q[0]))
    #define DYNAMICDEBUG(TY, NM, N)                                           
                printf("Showing type:" #TY ", variable name:" #NM "
    ");      
                showbst<TY>((NM),(N))

    optimalbst函数,生成二维数组root, p, q,并填充数据。注意:此时的root数组内容是下标从0开始的。

    int **optimalbst(float *p, float *q, int lengthp, int lengthq, float ***e, float ***w) {//返回root,记录着对应的索引
        if (lengthp <= 0 || lengthq <= 0) return NULL;
        int **root = new int *[lengthp], i, j;
        float t;
        *e = new float *[lengthq];
        *w = new float *[lengthq];
        for (i = 0; i < lengthp; i++)
            root[i] = new int[lengthp];
        for (i = 0; i < lengthq; i++) {
            (*e)[i] = new float[lengthq];
            (*w)[i] = new float[lengthq];
        }
        //初始化数据
        for (i = 0; i < lengthp; i++)
            for (j = 0; j < lengthp; j++)
                root[i][j] = -1;
        for (i = 0; i < lengthq; i++)
            for (j = 0; j < lengthq; j++)
                (*e)[i][j] = (*w)[i][j] = -1;
        //动态规划算法
        for (i = 0; i < lengthq; i++)
            (*e)[i][i] = (*w)[i][i] = q[i];
        for (int l = 1; l <= lengthp; l++)
            for (i = 1; i <= lengthp - l + 1; i++) {
                j = i + l - 1;
                (*w)[i - 1][j] = (*w)[i - 1][j - 1] + p[j - 1] + q[j];//i下标全部调整,j下标保持
                for (int r = i; r <= j; r++) {
                    t = (*e)[i - 1][r - 1] + (*e)[r][j] + (*w)[i - 1][j];
                    if ((*e)[i - 1][j] == -1.0f || t < (*e)[i - 1][j]) {
                        (*e)[i - 1][j] = t;
                        root[i - 1][j - 1] = r - 1;
                    }
                }
            }
        return root;
    }

    printfbst函数,解释root数组。注意:此时要将下标转换为原始数据的标号!!!

    void printfbst(int **root, int i, int j, int n) {
        if (i == 0 && j == n - 1)
            printf("k%d是根
    ", root[i][j]+1);
        if (i < j)
        {
            int index = root[i][j];
            if (index != i)
                printf("k%d是k%d的左节点
    ", root[i][index - 1] + 1, index + 1);
            printfbst(root, i, index - 1, n);
            if (index != j)
                printf("k%d是k%d的右节点
    ", root[index + 1][j] + 1, index + 1);
            printfbst(root, index + 1, j, n);
        }
        else if (i == j)
        {
            printf("d%d是k%d的左节点
    ", i, i + 1);
            printf("d%d是k%d的右节点
    ", i + 1, i + 1);
        }
        else
            printf("d%d是k%d的右节点
    ", j + 1, j + 1);
    }

    数据录入,从这里就看的出p数组的下标不满足C语言数组性质,所以我作了修改,让其满足,这样录入数据就非常方便了!!!

    float p[] = { 0.15,0.1,0.05,0.1,0.2 }, q[] = { 0.05,0.1,0.05,0.05,0.05,0.1 }

    完整的main函数,用于测试

    int main()
    {
        float p[] = { 0.15,0.1,0.05,0.1,0.2 }, q[] = { 0.05,0.1,0.05,0.05,0.05,0.1 }, **e, **w;//k1 - k5, d0-d5
        int **root;//root保存的是数组下标
        root = optimalbst(p, q, LENGTHP, LENGTHQ, &e, &w);
        DYNAMICDEBUG(float, e,LENGTHQ);
        DYNAMICDEBUG(float, w, LENGTHQ);
        DYNAMICDEBUG(int, root, LENGTHP);
        printf("解释最优二叉树,数组下标转换为实际的k1-k5, d0-d5
    ");
        printfbst(root, 0, LENGTHP-1, LENGTHP);
        freebst<int>(root, LENGTHP);
        freebst<float>(e, LENGTHQ);
        freebst<float>(w, LENGTHQ);
        return 0;
    }

    几个辅助函数,用于测试

    template <typename T>
    void freebst(T **p, int n) {
        for (int i = 0; i < n; i++)
            delete[] p[i];
        delete[] p;
    }
    
    template <typename T>
    void showbst(T **p, int n) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++)
                if ((float)p[i][j] != -1.0f)
                    printf("%.2f ", (float)p[i][j]);
                else
                    printf("%-05s", " ");
            printf("
    ");
        }
        printf("
    ");
    }

    测试结果:

    上图分别对应书上的结果图

    e数组, w数组,以及root数组。注意:再三强调,经过修改,root数组内容是指向数组下标的,而非实际的数据标号。

    再看对应的二叉树解释

    所有代码经过测试,结果正确!!!

  • 相关阅读:
    vsftp搭建
    进程管理相关命令(15 个)
    系统管理与性能监视命令 (9 个)
    系统权限及用户授权相关命令(4 个)
    用户管理命令(10个命令)
    深入网络操作命令(9条命令)
    查看系统用户登陆信息的命令(7 个)
    查看文件及内容处理命令(21个命令)
    有关磁盘与文件系统的命令(16个命令)
    linux kernel bisops.h
  • 原文地址:https://www.cnblogs.com/dalgleish/p/9133544.html
Copyright © 2020-2023  润新知