【算法设计与分析基础】22、最优二叉查找树

package cn.xf.algorithm.ch08DynamicProgramming;

import java.util.Arrays;

import org.junit.Test;

import cn.xf.algorithm.ch08DynamicProgramming.vo.ResultVo;

/**
 * 最优二叉树问题
 *
 * 思路:根据最优二叉树的问题就是查找对应的节点的比较次数的期望值保持最小
 * 最优二叉查找树的期望搜索代价保持最小
 * 例如:一颗树有节点{k0,k1,k2,k3....kn} 对应搜索概率是:{p0,p1,p2....pn}
 * 那么根据二叉的深度设定对应的代价,那么就是
 * depth(ki) * pi + ..... 所有的都加起来,那么就是期望搜索代价
 * .
 *
 * @版权:福富软件 版权所有 (c) 2017
 * @author xiaof
 * @version Revision 1.0.0
 * @see:
 * @创建日期:2017年8月9日
 * @功能说明:
 *
 */
public class BinaryTreeBest {

    /**
     * 对于这个概率求最优二叉查找树
     * 这里的关键是C[1,0] = 0  C[1,1] = Pi  前者作为空树存在,后者作为单节点树
     * @param probabilities
     */
    public ResultVo optimalBST(double probabilitiesT[]) {
        if(probabilitiesT == null || probabilitiesT.length <= 0) {
            return null;
        }

        //初始化,最优二叉查找树的期望搜索代价数组,以及主键最优二叉树的数组
        //数组后置一位,并把开头设置为空
        double probabilities[] = new double[probabilitiesT.length + 1];
        for(int i = 1; i < probabilities.length; ++i) {
            probabilities[i] = probabilitiesT[i - 1];
        }

        double C[][] = new double[probabilities.length + 1][probabilities.length + 1];
        int R[][] = new int[probabilities.length + 1][probabilities.length + 1];
        for(int i = 0; i < probabilities.length; ++i) {
            C[i][i] = probabilities[i]; //这个是单节点情况,
            R[i][i] = i;
        }

        //遍历所有的节点数量海数据,遵循公式 C[i,j] = (i->j)p + min{(i->k-1)depth(ki)pi + (k+1->j)depth(ki)pi }
        //根据对角线的差距数据获取值,因为递归求出的值得顺序是
        //C[1,2], C[2,3], C[3,4],C[4,5],C[5,6]....
        //C[1,3], C[2,4], C[3,5],C[4,6],C[5,7]....
        //C[1,4], C[2,5], C[3,6],C[4,7],C[5,8]....
        //这些数据以对角线的模式递增,数据之间的差距在慢慢变大,在C[1,N]之前的差额数据还是n-1,那么就是比如5个节点,就是4
        for(int d = 0; d < probabilitiesT.length; ++d) {
        	//这个是循环i与j的差距大小
        	//接下来循环开始位置,个数是实际的节点个数
        	for(int start = 1; start < probabilitiesT.length; ++start) {
        		//起始位置,然后根据当前差距,判定后面的位置j
        		int endj = start + d;
        		//超出当前循环最大长度
        		if(endj >= C[0].length - 1) {
        		    continue;
        		}
        		double min = Integer.MAX_VALUE; //设定当前最小值,作为一个起始判断对象
        		int kmin = start;
        		//设定中间划分点,只有两个不等,或者后面endj比start大的时候才可以进入递推队列
        		if(start != endj) {
        		    for(int midk = start; midk <= endj; ++midk) {
                        //判断当前分区的位置是否是最小的
                        if(midk + 1 < C.length && C[start][midk - 1] + C[midk + 1][endj] < min) {
                            //如果是这个选中的k的中间断点的最优二叉查找树
                            min = C[start][midk - 1] + C[midk + 1][endj];
                            kmin = midk;
                        }
                    }

        		    //统计start到endj的概率和
                    double sum = 0;
                    for(int i = start; i <= endj; ++i) {
                        sum += probabilities[i];
                    }
                    C[start][endj] = sum + min;
                    R[start][endj] = kmin;
        		}
        	}
        }
        ResultVo resultVo = new ResultVo();
        resultVo.setC(C);
        resultVo.setR(R);
        return resultVo;
    }

    @Test
    public void test1() {
    	double probabilities[] = {0.15, 0.10, 0.05, 0.10, 0.20};
//    	double probabilities[] = {0.1, 0.2, 0.4, 0.3};
    	BinaryTreeBest btb = new BinaryTreeBest();
    	ResultVo resultVo = btb.optimalBST(probabilities);
    	System.out.println();
    	//输出最优查找期望阵列
    	System.out.println("最优查找期望阵列");
    	double C[][] = resultVo.getC();
    	for(int i = 0; i < C.length; ++i) {
    	    for(int j = 0; j < C[0].length; ++j) {
    	        System.out.print(C[i][j] + "\t");
    	    }
    	    System.out.println();
    	}

    	//二叉树构建矩阵
    	System.out.println("二叉树构建矩阵");
    	int R[][] = resultVo.getR();
    	for(int i = 0; i < R.length; ++i) {
            for(int j = 0; j < R[0].length; ++j) {
                System.out.print(R[i][j] + "\t");
            }
            System.out.println();
        }
    }
}

  

截图:

结果:

时间: 2024-10-07 21:17:01

【算法设计与分析基础】22、最优二叉查找树的相关文章

算法设计与分析基础(第3版)读书笔记(及几处翻译上的错误~~)

算法设计与分析基础(第3版) p16 in-place翻译为'在位'?'就地'更合适点 p38 amortized应翻译为'均摊','摊销'这个词简直莫名其妙(可能因为翻译是做算法交易导致的?) p64 迭代优于递归(迭代始终是增量式的,而递归就没办法增量了,除非能够dump整个运行时栈) p73 通过算法可视化得到一个更好的非递归算法(人的图像认知直觉思维?) p79 验证一个拓扑是环.星.还是团?(这个地方有点意思,因为我想到了动态的Verify) p87 凸包问题:从数据结构上讲,Set<

【算法设计与分析基础】大整数乘法

#include<iostream> #include<string> #include<time.h> #include<stdlib.h> #include<sstream> using namespace std; class BigDecimal{ private: int max(int a,int b){//获取两数中的最大值 return a^((a^b) & -(a<b)); } public: string n;

【算法设计与分析基础】关灯游戏

① R.java  用于存储一些全局变量 package lightoff; public class R { /* public static int lightCondition[][] = { {1,0,0,1,1}, {1,0,0,1,1}, {1,0,0,1,1}, {1,0,0,1,1}, }; */ public static int lightCondition[][] = { {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, }; //灯面

【算法设计与分析基础】19、字符串匹配算法

package cn.xf.algorithm.ch07inputEnhancement; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; /** * * 功能:字符串匹配算法,(还有一种叫KMP算法的,也是很经典的算法,就是比较复杂) * * 第一步:对于给定的长度为m的模式和在模式文本中用到的字母表,按照上面的描述构造移动表 * 第二步:将模式与文本的开

【算法设计与分析基础】16、高斯消元法

package cn.xf.algorithm.ch06ChangeRule; import java.util.ArrayList; import java.util.List; import org.junit.Test; import cn.xf.util.GenericPair; /** * * 功能:高斯消元法,也就是多元数据矩阵,依次吧每列的其他行数据消去为0,然后求出一个元的解,然后就可以根据这个数据来递推出其他元的解 * @author xiaofeng * @date 2017

【算法设计与分析基础】20、动态规划-硬币搜集问题

题目: 在n*m格木板中放有一些硬币,每格的硬币数目最多为一个.在木板左上方的一个机器人需要搜集尽可能多的硬币并把他们带到右下方的单元格,每一步,机器人可以从当前的位置向右移动一格 或者向下移动一格,当机器人遇到一个有硬币的单元格的时,就会将这枚硬币搜集起来 解题: 硬币收集的时候,我们 从结果状态开始看,当搜集当前硬币的时候,只有两种方式,从上往下搜集,或者从左向右搜集 也就是当前f[i,j] = max{f[i, j - 1], f[i - 1, j]},初始化第一行和第一列,从第二行和列开

【算法设计与分析基础】17、堆

以数组来存放堆数据 package cn.xf.algorithm.ch06ChangeRule; import java.util.ArrayList; import java.util.List; import org.junit.Test; /** * * 功能:堆的构造 * 1.堆可以定义为一颗二叉树,树的节点包含键,并且满足一下条件 * 1) 树的形状要求:这棵二叉树是基本完备的(完全二叉树),树的每一层都是满的,除了最后一层最右边的元素可能缺位 * 2) 父母优势,堆特性,每一个节点

【算法设计与分析基础】18、霍纳法则

产生随机数 package cn.xf.algorithm.ch02; import java.util.ArrayList; import java.util.List; /** * 生产随机数 * @author xiaof * */ public class Random { /** * 生产一个随机数的数列 * @param n 生成n个数列 * @param m 数据在0和m-1之间 * @param seed 随机初始种子 * @param a 参数 * @param b 参数 *

【算法设计与分析基础】23、堆排序-2

package cn.xf.algorithm.ch09Greedy.util; import java.util.ArrayList; import java.util.List; /** * 堆构造以及排序 * * .功能:堆的构造 * 1.堆可以定义为一颗二叉树,树的节点包含键,并且满足一下条件 * 1) 树的形状要求:这棵二叉树是基本完备的(完全二叉树),树的每一层都是满的,除了最后一层最右边的元素可能缺位 * 2) 父母优势,堆特性,每一个节点的键都要大于或者等于他子女的键(对于任何叶