欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

二叉最优搜索树java实现

程序员文章站 2023-12-26 23:59:15
...
package com.bysj.common.算法.动态规划;

/**
* 二叉最优搜索树使用场景:
*
* 现在我有一张英文单词的文章,我要根据字典翻译为中文,所以我先要把字典构造成一个二叉最优搜索树,其中有的字搜索频率很高比如:草,爱,做等
* 所以我先给每个字定义一个频率q,这样每次搜索一个字的时候所需要的消耗就是pi*(depth{ki}+1){算法导论有论证};现在我们要构造一个遍历所有节点的时候消耗最低的
* 二叉树;
*
* 思路:
* 0.(暴力法)每个节点每个位置都要计算一次,所以是2的n次方效率(傻逼)
* 1.首先我们肯定要遍历所有的节点作为根节点的情况
* 2.既然我们要遍历所有节点,但是可以通过动态规划避免求很重复的子树
* 3.动态规划算法的精髓:
* {3.1:构造一个子最优解T,如果T是最优解,那么T1的子树也必定是最优解,证明:T1不是最优解则存在最优解T2,用T2替换T1就会得到更优的T与假设不相符
* 3.2:我们需要从(ki,ki+1,...,kj)中选择一个跟结点kr,然后分别构造其左子树和右子树。下面需要计算以krE为根的树的期望搜索代价。然后选择导致最小期望搜索代价的kr做根。
* 3.2:我们使用自底向上的方法遍历(自顶向下也可以,使用备忘录)
* }
*/
public class 二叉最优搜索树 {
public static void main(String[] args) {
double[] p = {0, 0.15, 0.1, 0.05, 0.1, 0.2}; //n=5关键字有5个
double[] q = {0.05, 0.1, 0.05, 0.05, 0.05, 0.1}; //叶子结点有n+1 = 6个
///这里的关键字长度为5
int n = p.length;

System.out.println("输出根节点辅助表");
int[][] root = Optimal_BST(p, q, n - 1);
int temp = root.length - 1;
for (int i = 1; i < temp; i++) {
for (int j = 1; j < temp; j++) {
System.out.print(root[i][j] + "-");
}
System.out.println();
}

printOptimalBST(root, 1, 5, root[1][5]);
}

/**
* DP在计算最优二叉树的辅助表的算法实现
*
* @param p
* @param q
* @param n
* @return
*/
private static int[][] Optimal_BST(double[] p, double[] q, int n) {
double[][] e = new double[n + 2][n + 2];//
double[][] w = new double[n + 2][n + 2];
int[][] root = new int[n + 2][n + 2];

//初始化叶子结点的值
for (int i = 1; i <= n + 1; i++) {
e[i][i - 1] = q[i - 1];
w[i][i - 1] = q[i - 1];
}
for (int l = 1; l <= n; l++) {///最外层循环是逐渐的将关键字个数从一个扩展到n个
for (int i = 1; i <= n - l + 1; i++) {
int j = i + l - 1;
e[i][j] = Double.MAX_VALUE;
w[i][j] = w[i][j - 1] + p[j] + q[j];//备忘录记录每个次数据
for (int r = i; r <= j; r++) {
double t = e[i][r - 1] + e[r + 1][j] + w[i][j];
if (t < e[i][j]) {
e[i][j] = t;
root[i][j] = r;///存储根节点的位置
}
}
}


}

System.out.println("输出当前的最小代价:" + e[1][n]);
return root;

}

/**
* 构建最优二叉搜索树
*
* @param root
* @param i
* @param j
* @param k
*/
private static void printOptimalBST(int[][] root, int i, int j, int r) {
int rootChild = root[i][j];
if (rootChild == r) {
System.out.println("K" + rootChild + "是根");
printOptimalBST(root, i, rootChild - 1, rootChild);
printOptimalBST(root, rootChild + 1, j, rootChild);
return;
}
if (j < i - 1) {
return;
} else if (j == i - 1)//遇到虚拟键
{
if (j < r) {
System.out.println("d" + j + "是" + "k" + r + "的左孩子");
} else {//j>=r
System.out.println("d" + j + "是" + "k" + r + "的右孩子");
}
return;
} else//遇到内部结点
{
if (rootChild < r) {
System.out.println("k" + rootChild + "是" + "k" + r + "的左孩子");
} else {
System.out.println("k" + rootChild + "是" + "k" + r + "的右孩子");
}

}

printOptimalBST(root, i, rootChild - 1, rootChild);
printOptimalBST(root, rootChild + 1, j, rootChild);

}


}

贴一张算法导论的自下而上的图:

 

二叉最优搜索树java实现

相关标签: 基础算法学习

上一篇:

下一篇: