1. 程式人生 > >最優二叉查詢樹_動態規劃

最優二叉查詢樹_動態規劃

 

原問題是給出各個節點和各個節點的被查詢概率,然後構造一棵各個節點平均被查詢比較次數最小的樹,則該問題可以用動態規劃來解決

示例如下

推廣到一般的情況,並設T(i, j)是由記錄{ri, …, rj}(1≤i≤j≤n)構成的二叉查詢樹,C(i, j)是這棵二叉查詢樹的平均比較次數,有下列分析

觀察這個表,可知可知左邊的表的第一行的第四列就是我們要求的最優平均比較次數,而右邊的表我們可以知道在c(i ,j)得到最優解,即平均查詢次數最小的根節點,比如一共四個節點,則我們從右邊的R(1,4)的值即3是這四個節點構成的樹的根節點。則樹的左子樹變為c(1,2),他的根節點是r(1,2)=2,然後2又有左節點1,而4則是3的根節點。則樹的樣子便出來了。

程式碼如下

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 double BST(int n,double p[],double c[][100],int r[][100])
 4 {
 5     for(int i=1;i<=n;i++){//按式1和式2初始化
 6         c[i][i-1]=0;
 7         c[i][i]=p[i];
 8         r[i][i]=i;
 9     }
10     c[n+1][n]=0;
11     for(int d=1;d<n;d++){//
安對角線計算,此時是n-1個對角線 12 for(int i=1;i<=n-d;i++){//行的取值範圍 13 int j=i+d;//求出在對角線上的i對應的j 14 double minnum=99999.0;//出是一個較大的值 15 int mink=i; 16 double sum=0; 17 for(int k=i;k<=j;k++) 18 { 19 sum=sum+p[k];
20 if(c[i][k-1]+c[k+1][j]<minnum){//不斷比較,獲取最小的值 21 minnum=c[i][k-1]+c[k+1][j]; 22 mink=k; 23 } 24 } 25 c[i][j]=minnum+sum;//得到了最小值 26 r[i][j]=mink;//記錄取得最小值時的根節點 27 } 28 29 } 30 return c[1][n]; 31 } 32 int main() 33 { 34 cout << "請輸入樹的節點的個數" << endl; 35 int n; 36 cin >> n; 37 cout << "請輸入每個節點的被查詢概率" << endl; 38 double p[n]; 39 memset(p,0,sizeof(p)); 40 for(int i=1;i<=n;i++) 41 { 42 cin >> p[i]; 43 } 44 double c[n+2][100]; 45 int r[n+2][100]; 46 memset(r,0,sizeof(r)); 47 memset(c,0,sizeof(c)); 48 double s=BST(n,p,c,r); 49 cout << "最小平均比較次數為" << s<<endl; 50 cout << "平均最小概率矩陣如下:" << endl; 51 for(int i=1;i<=n+1;i++){ 52 for(int j=0;j<=n;j++){ 53 cout << c[i][j] << " "; 54 } 55 cout << endl; 56 } 57 58 cout << "最優二叉查詢樹對應的根節點 " << endl; 59 for(int i=1;i<=n+1;i++){ 60 for(int j=0;j<=n;j++){ 61 cout << r[i][j] << " "; 62 } 63 cout << endl; 64 } 65 66 return 0; 67 }

執行結果如下

具體樹的構造我們可以從陣列r求出,等我有空再把程式碼補上,用程式把樹的構造描繪出來