二叉搜索树 -【动态规划】最优C++实现

本文介绍了一种使用动态规划求解最优二叉搜索树的算法,并提供了完整的C++实现代码。该算法通过预处理概率数据并计算不同子树的最佳根节点来最小化平均查找成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序在VC++6.0下编译通过

   
1 #include < iostream > 2 #include < fstream > 3 #include < string > 4 #include < limits > 5 6   using namespace std; 7 8 const string INFILE = " in.txt " ; // 存放“输入数据”的文件 9 const string OUTFILE = " out.txt " ; // 存放“输出数据”的文件 10 const int N = 7 ; // 结点数 11 const double MAX = numeric_limits < double > ::max(); // double的最大值 12 const double MAXMAX = numeric_limits < long > ::max(); // double的最大值 13 14 double p[N + 2 ]; // p[i]为结点i被访问的概率 15 double q[N + 2 ]; // q[i]为“虚结点”i被访问的概率 16 // double e[(N+2)*(N+2)]; // e,用来存放子树(i,j)的期望代价 17 double e[N + 2 ][N + 2 ]; 18 // double w[(N+2)*(N+2)]; // w,用来存放子树(i,j)的所有结点(包括虚结点)的p、q之和 19 double w[N + 2 ][N + 2 ]; 20 // int root[(N+2)*(N+2)]; // root,用来跟踪root的 21 int root[N + 2 ][N + 2 ]; 22 23 24 // void optimalBst(double *p, double *q, int n) 25 void optimalBst( void ) 26 { 27 int i,j,l,r; // i,j用来标记“子树(i,j)”;l用来标记“步长”;r用来标记子树的根节点(动态规划的“选择”) 28 29 // 这是个很boundary的case:当j=i-1的时候,“子树(i,j)”实际上是“虚结点i-1”*/ 30 for (i = 1 ; i <= N + 1 ; ++ i) 31 { 32 e[i][i - 1 ] = q[i - 1 ]; 33 w[i][i - 1 ] = q[i - 1 ]; 34 } 35 36 // 用“动态规划”方法,自底向上构造“最优二叉搜索树”的解 37 for (l = 1 ; l <= N ; ++ l) // 步长l从小到大 38 { 39 for (i = 1 ; i <= N - l + 1 ; ++ i) // 步长为l的情况下,i的范围是1到N-l+1 40 { 41 j = i + l - 1 ; // 此时步长为l,j的值为i+l-1 42 e[i][j] = MAX; 43 w[i][j] = w[i][j - 1 ] + p[j] + q[j]; // 对于“子树(i,j)”来说,不管树形是什么样的,w[i,j]的值都是固定的 44 45 // 在i--j中,选择一个r作为“最佳根节点” 46 double temp = MAX; 47 for (r = i ; r <= j; ++ r) 48 { 49 temp = e[i][r - 1 ] + e[r + 1 ][j] + w[i][j]; 50 if (temp < e[i][j]) 51 { 52 e[i][j] = temp; 53 root[i][j] = r; 54 } 55 } 56 } 57 } 58 59 60 } 61 62 int main() 63 { 64 int i,j; 65 ifstream fIn(INFILE.c_str()); // 文件“读入流” 66 ofstream fOut(OUTFILE.c_str()); // 文件“输出流” 67 68 // 从文件读入输入数据 69 i = 1 ; 70 while ( ! fIn.eof()) 71 { 72 if (i <= N) 73 { 74 fIn >> p[i]; 75 } 76 else 77 { 78 fIn >> q[i - N - 1 ]; 79 } 80 ++ i; 81 } 82 83 // 用“动态规划”计算“最优二叉搜索树” 84 // optimalBst(p,q,N); 85 optimalBst(); 86 87 // 打印结果 88 for (i = 0 ; i <= N + 1 ; ++ i) 89 { 90 for (j = 0 ; j <= N + 1 ; ++ j) 91 { 92 fOut << " e[ " << i << " , " << j << " ] = " << e[i][j] << endl; 93 } 94 } 95 fOut << endl << endl; 96 for (i = 0 ; i <= N + 1 ; ++ i) 97 { 98 for (j = 0 ; j <= N + 1 ; ++ j) 99 { 100 fOut << " w[ " << i << " , " << j << " ] = " << w[i][j] << endl; 101 } 102 } 103 fOut << endl << endl; 104 for (i = 0 ; i <= N + 1 ; ++ i) 105 { 106 for (j = 0 ; j <= N + 1 ; ++ j) 107 { 108 fOut << " root[ " << i << " , " << j << " ] = " << root[i][j] << endl; 109 } 110 } 111 112 cout << " 大丈夫、萌大奶,去 " << OUTFILE << " 里查看结果吧少年! " << endl; 113 cout << MAXMAX << endl; 114 115 return 0 ; 116 }
分类: 算法
### 动态规划实现最优二叉搜索树 动态规划是一种解决复杂问题的有效方法,通过将其分解为更小的子问题来逐步求解。对于构建最优二叉搜索树(OBST),其目标是最小化平均搜索成本。以下是基于动态程序设计算法实现及其解释。 #### 算法概述 为了找到一棵具有最小预期搜索代价的二叉搜索树,可以采用动态规划技术。该过程涉及计算不同节点作为根时的成本,并选择使总成本最低的那个配置[^1]。 #### 关键概念 - **n**: 节点总数。 - **p[i]**: 第 i 个关键字 ki 的查找概率。 - **q[i]**: 在区间 (ki, ki+1) 中找不到任何关键字的概率。 - **e[i][j]**: 表示从第 i 到 j 构建 OBST 所需期望成本。 - **w[i][j]**: 子链表 {Ki,...Kj} 上所有 p 和 q 值之和。 #### C++ 示例代码 下面提供了一个简单的 C++ 版本的实现: ```cpp #include <iostream> #include <vector> using namespace std; void printSolution(int root[][], int n){ cout << "Roots of the optimal BST:" << endl; for (int i=0; i<=n; ++i) cout << root[i][n] << ' '; } // Function to get optimum cost and construct tree. double optCost(vector<double> &p, vector<double> &q, int n){ // Initialize tables e[][] and w[][] double e[n+2][n+1]; double w[n+2][n+1]; // Root table will store roots of subtrees optimized over different ranges. int root[n+1][n+1]; for (int i=0;i<=n;i++) { e[i][i-1]=q[i]; w[i][i-1]=q[i]; } for (int l=1;l<=n;l++){ for (int i=0;i<=n-l;i++){ int j=i+l; e[i][j]=INFINITY; w[i][j]=w[i][j-1]+p[j]+q[j]; for (int r=i;r<j;r++){ double t=e[i][r-1]+e[r+1][j]+w[i][j]; if(t<e[i][j]){ e[i][j]=t; root[i][j]=r; } } } } return e[0][n]; } int main(){ int keys[]={10,12,20}; double p[]= {0.35,0.25,0.4}; // probabilities of searching each key double q[]= {0.05,0.1,0.05,0.1}; // probabilities when not found between or outside int n=sizeof(keys)/sizeof(keys[0]); printf("Expected Cost is %.6f\n",optCost(p,q,n)); } ``` 此代码片段展示了如何利用给定的关键字集合以及它们对应的访问频率来创建一颗最优二叉搜索树[^3]。 #### JavaScript 实现 同样地,在 JavaScript 中也可以实现这一逻辑: ```javascript function buildObst(p, q, n) { let e = Array.from({ length: n + 2 }, () => new Array(n + 1).fill(0)); let w = Array.from({ length: n + 2 }, () => new Array(n + 1).fill(0)); let root = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(0)); for(let i = 0; i <= n; i++) { e[i][i - 1] = q[i]; w[i][i - 1] = q[i]; } for(let L = 1; L <= n; L++) { for(let i = 0; i <= n - L; i++) { let j = i + L; e[i][j] = Infinity; w[i][j] = w[i][j - 1] + p[j] + q[j]; for(let r = i; r < j; r++) { let temp = e[i][r - 1] + e[r + 1][j] + w[i][j]; if(temp < e[i][j]) { e[i][j] = temp; root[i][j] = r; } } } } console.log('The expected search cost:', e[0][n]); function printTree(i,j){ if(j<i) return ''; else{ const k=root[i][j]; return '('+printTree(i,k-1)+','+ String.fromCharCode(k+'A'.charCodeAt()-1)+ ','+printTree(k+1,j)+')'; } } console.log(printTree(0,n)); } let p=[null,.3,.3,.4]; let q=[.2,null,.2,.2,.1]; buildObst(p,q,3); ``` 上述脚本实现了相同的动态规划策略用于寻找最佳结构并打印出来[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值