最優二叉搜尋樹(JAVA實現)
阿新 • • 發佈:2018-12-02
演算法課上老師講的最優二叉搜尋樹,自己又查了些資料才看明白。這篇只記錄下自己用java的實現和自己的一些細節的理解。想學習整個演算法的可以參照 https://blog.csdn.net/zhangyifei521/article/details/50833792
package bestBinarySearchTree;
public class writebyjeff {
public static void main(String[] args) {
//p[1,5]是5個實節點的概率 p[0]不存在
double[] p = {
0,0.15,0.1,0.05,0.1,0.2
} ;
//q[0,5]是6個虛節點的概率
double[] q= {
0.05,0.1,0.05,0.05,0.05,0.1
};
//共5個
int n = p.length - 1;
//root[i][j]記錄的是最終得出的[i,j]這個子段裡的根節點
int[][] root = Optimal_BST(p,q,n);
//root的length是n+2,i和j只需要迴圈到n
int temp = root.length - 1;
//輸出一下這個root矩陣,直接根據這個矩陣也可以自己畫出來最優二叉搜尋樹了
for(int i = 1;i < temp; i++) {
for(int j = 1; j < temp; j++) {
System.out.print(root[i][j] + "-");
}
System.out.println();
}
}
private static int[][] Optimal_BST(double[] p, double[] q, int n) {
//e[i][j]表示i到j這段的代價
//e[1][0]為左邊虛節點d0的代價...e[n+1][n]為左邊虛節點dn的代價
double[][] e= new double[n+2][n+2];
//i到j這一段的總概率,在加一層根節點時需要用到
double[][] w= new double[n+2][n+2];
//root[i][j]記錄的是最終得出的[i,j]這個子段裡的根節點
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];
}
//這段程式碼需要好好理解
//l是 [i,j]的長,相當於一個固定l長度的小節從最左邊迴圈到最右邊。然後再把l逐漸加大,重複從左到右。這樣就使得小長度的都先計算過,為大長度的片段分解為左右兩個字片段計算時提供了已經計算好的值,這也是動態規劃的精髓之一。
//這樣做是為了從小到大積累動態規劃的能量
for(int l = 1; l <= n; l++) {
for (int i = 1; i <= n-l+1; i++) {
int j = i + l - 1;
//先設為最大值,最後才能找出真正最小的,從而找到最優解
e[i][j] = Double.MAX_VALUE;
//w的遞迴,很容易理解
w[i][j] = w[i][j-1] + p[j] + q[j];
//從i到j找到最優的根節點
for(int r = i; r <= j; r++) {
//加了一層,相當於下面的左子樹右子樹都加了一布,其實就是最終比沒加一層根節點比多了一個w[i][j]
double t = e[i][r-1] + e[r+1][j] + w[i][j];
//不斷的使e[i][j]保持最小,同時記錄使代價最小的位置為最終最優的根節點
if(t < e[i][j]) {
e[i][j] = t;
root[i][j] = r;
}
}
}
}
System.out.println("當前最小代價:" + e[1][n]);
return root;
}
}