第十五章動態規劃之“最優二叉查詢樹”
阿新 • • 發佈:2019-01-02
本書從文字翻譯的案例切入,假設把英文翻譯為法文,每個英文單詞為關鍵字,其對應法文為衛星資料。用二叉查詢樹儲存,該怎麼設計這個查詢樹。即使是紅黑樹,查詢的時間複雜度也為O(lgn)即樹的深度。但是因為文章中某個單詞出現的頻率不同,所以可能有些頻率很高的單詞比如the的深度可能很深,而不常見的Aha的深度卻可能很淺。根據直覺,我們應該讓本例中the更加靠近樹根才對(其實即使概率最高也不見得就是樹根)。我們應該讓查詢整個樹的期望次數最小,即構建一個最優二叉查詢樹。一個最優二叉查詢樹的左右子樹的肯定也是最優的。陣列p中是k1~k5的概率。k1到k5是從小到大的順序,即字典序。當找不到要查詢到英文單詞時肯定最終會走到樹葉,每個樹葉出現的概率儲存到陣列q中。我一直沒弄明白這個樹葉的概率作者是怎麼搞出來的。誰知道告訴我一下。
程式一個注意的地方就是浮點數比較,不能直接比較,除非相差很大才行,如果兩個浮點數相等,要是直接使用大於號進行判斷也有可能成立。
程式碼如下:
#include <iostream> using namespace std; void OpticalBST(double *p,double *q,int n,double (*e)[6],int (*root)[6]) { double w[n+1][6]; 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++) { for(int i=1;i<=n-l+1;i++) { int j=i+l-1; e[i][j]=1<<30; //cout<<e[i][j];system("pause"); w[i][j]=w[i][j-1]+p[j]+q[j];//子樹i...j的總概率 for(int r=i;r<=j;r++) { double t=e[i][r-1]+e[r+1][j]+w[i][j]; if(e[i][j]-t>0.0000000001)//不能直接用e[i][j]>t,因為如果e[i][j]和t都是浮點數,即使相等的話,相減可能也不等於0 { e[i][j]=t; root[i][j]=r; } } } } } void ConstructOpticalBST(int (*root)[6],int i,int j) { if(i==1&&j==5) { cout<<"k"<<root[i][j]<<"是根"<<endl;//system("pause"); } if(i<root[i][j]) { cout<<"k"<<root[i][root[i][j]-1]<<"是k"<<root[i][j]<<"的左孩子"<<endl; ConstructOpticalBST(root,i,root[i][j]-1); } else { cout<<"d"<<root[i][j]-1<<"是k"<<root[i][j]<<"的左孩子"<<endl; } if(root[i][j]<j) { cout<<"k"<<root[root[i][j]+1][j]<<"是k"<<root[i][j]<<"的右孩子"<<endl; ConstructOpticalBST(root,root[i][j]+1,j); } else { cout<<"d"<<root[i][j]<<"是k"<<root[i][j]<<"的右孩子"<<endl; } } int main() { int n=5; double p[6]={0,0.15,0.1,0.05,0.1,0.2};//第一個不用。1~5分別代表k1~k5,並且k1~k5是按從下到大順序排列。K的順序對於輸出整個數很重要。 double q[6]={0.05,0.1,0.05,0.05,0.05,0.1}; double e[7][6]; int root[6][6]; OpticalBST(p,q,n,e,root); ConstructOpticalBST(root,1,5); system("pause"); return 0; }