最优二叉搜索树
首先了解什么是二叉查找树:
给定n个互异的关键字组成的序列s=<k1,k2,…,kn>,且关键字有序(k1<k2<…<kn),我们想从这些关键字中构造一棵二叉查找树。对每个关键字ki,一次搜索搜索到的概率为pi。可能有一些搜索的值不在K内,因此还有n+1个“虚拟键”d0,d1,…,dn,他们代表不在K内的值。具体:d0代表所有小于k1的值,dn代表所有大于kn的值。而对于i = 1,2,…,n-1,虚拟键di代表所有位于ki和ki+1之间的值。对于每个虚拟键,一次搜索对应于di的概率为qi。要使得查找一个节点的期望代价(代价可以定义为:比如从根节点到目标节点的路径上节点数目)最小,就需要建立一棵最优二叉查找树
程序代码
package ch01;
public class BinarySearchTree {
public void optimalBinarySearchTree(float[] a,float[] b,float[][] m,int[][] s,float[][] w){
int n=a.length-1;
for(int i=0;i<=n;i++){//初始化构造无内部节点的情况
w[i+1][i]=a[i];
m[i+1][i]=0;
}
for(int r=0;r<n;r++){//r为i与j之间的差值
for(int i=1;i<=n-r;i++){
int j=i+r;
//i,j之间距离为r时,首选i为根,其左子树为空,右子树为节点
w[i][j]=w[i][j-1]+a[j]+b[j];//计算w[i][j]
m[i][j]=m[i+1][j];
s[i][j]=i;
for(int k=i+1;k<=j;k++){//i<=k<=j,通过k循环,找到min{m(i,k-1)+m(k+1,j)}的值
float temp=m[i][k-1]+m[k+1][j];
if(temp<m[i][j]){
m[i][j]=temp;
s[i][j]=k;//k作为根节点
}
}
m[i][j]+=w[i][j];//m(i,j)=wi,j+min{m(i,k-1)+m(k+1,j)}
}
}
}
public void backtrace(int[][] s,int n,int i,int j,int p,String str){
int k=s[i][j];
if(k>0){
if(p==0){
System.out.println("root is:"+k);
}else{
System.out.println(str+" of "+p+" is "+k+"; and (i:j) is "+i+":"+j);
}
int t=k-1;
if(t>=i&&t<=n)
backtrace(s,n,i,t,k,"left");
t=k+1;
if(t<=j)
backtrace(s,n,t,j,k,"right");
}
}
public static void main(String[] args) {
float a[] = {0.15f,0.1f,0.05f,0.05f};//a,b的下标都是从0开始
float b[] = {0.00f,0.5f,0.1f,0.05f};
int n=a.length-1;
float[][] m=new float[n+2][n+2];
int[][] s=new int[n+2][n+2];//因为w[i+1][i]存在,i最大为n,即可以从0.....n,n+1,共n+2个
float[][] w=new float[n+2][n+2];
BinarySearchTree bi = new BinarySearchTree();
bi.optimalBinarySearchTree(a, b, m, s, w);
System.out.println("二叉搜索树最小平均路长为:"+m[1][n]);
bi.backtrace(s, n, 1, n, 0, "0");
}
}