最優二叉搜索樹算法的java實現(動態規劃法)
具體問題描述以及C/C++實現參見網址
http://blog.csdn.net/liufeng_king/article/details/8694652
未改進版的java代碼如下:
/**
* 最優二叉搜索樹(動態規劃)---未改進版
* @author Lican
*
*/
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");
}
}
算法實現結果如圖:===================================================================================================================================
改進後的java代碼如下(具體改進的地方,參見引文中的介紹)
/**
* 最優二叉搜索樹(動態規劃)---改進版
* @author Lican
*
*/
public class BinarySearchTree2 {
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;
s[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;
/*以下爲 改進後的地方*/
int i1=s[i][j-1]>i?s[i][j-1]:i;
int j1=s[i+1][j]>i?s[i+1][j]:j;
//i,j之間距離爲r時,首選i爲根,其左子樹爲空,右子樹爲節點
w[i][j]=w[i][j-1]+a[j]+b[j];//計算w[i][j]
m[i][j]=m[i][i1-1]+m[i1+1][j];//k=i1時的情況
s[i][j]=i1;
//左子樹爲節點:i1,i1+1……k-1,右子樹爲節點:k+1,k+2,……j1
for(int k=i1+1;k<=j1;k++){//i1<=k<=j1,通過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");
}
}
運行結果與未改進版相同。