最优二叉查找树的详细分析,c++代码实现
来源:互联网 发布:赫子铭离婚 知乎 编辑:程序博客网 时间:2024/05/21 10:06
首先看下关于最优二叉查找树的描述
给定一个由n个互异的关键字组成的序列K={k1,k2,...,kn},且关键字有序,对于每一个关键字ki,一次搜索为ki的概率是pi。某些搜索的值可能不在K内,因此还有n+1个虚拟键d0,d1,...,dn代表不再K内的值。d0代表所有小于k1的值,dn代表所有大于kn的值,对于i=1,2,...,n-1,di代表所有位于ki和ki+1之间的值。对每个虚拟键di,一次搜索对应于di的概率是qi。定义在T内一次搜索的期望代价为E=∑(depth(ki)+1)*pi+∑(depth(di)+1)*qi=1+∑depth(ki)*pi+∑depth(di)*qi
要找的最小的E则为最优二叉查找树
首先,我们定义
w[i][j] = q[i-1]+p[i]+q[i]+p[i+1] + .... +q[j]+p[j], 显然w[i][j] = w[i][j-1] + q[j]+p[j]
E[i][j]为由结点i到j构成的最优二叉查找树的期望代价,如果我们假设它的根为r,那么,显然,他的左子树(由结点i,i+1,...r-1构成)也是一棵最优二叉查找树,右子树也是一棵最优二叉查找树,否则,我们可以调整他的子树,便得到一棵比原先更优的二叉查找树,与前提矛盾,所以,最优二叉查找树具有最优子结构
单单就左子树的查找代价为E[i][r-1]
单单就右子树的查找代价为E[r+1][j]
而将左子树和右子树作为子树连接到一个根r上面,显然,整体的查找代价增加了p[r] +( q[i-1]+p[i]+...q[r-1] )[注:左子树增加的,因为所有的实结点和虚节点均多了一层]+ (q[r+1]+p[r+1]+...q[j])[注:右子树增加的代价]
增加的代价其实转换一下就是w[i][j]
那么,E[i][j] = E[i][r-1] + E[r+1][j] + W[i][j] (r=i, ...j)
要使得E[i][j]最小,就要选取合适的r用公式表达即为
E[i][j] = min{E[i][r-1] + E[r+1][j] + W[i][j] }(r=i, ...j)
注意E[i][i-1]定义为q[i-1],同理E[j+1][j]为q[j]原因是因为r=i,或j的时候虽然左或右子树虽然为空,但是依旧包括虚节点d[i-1]以及d[j],如果想不通的话可以通过E[i][i]反推E[i][i-1]
反推如下
E[i][i] = E[i][i-1] + E[i+1][i] + W[i][i] //相当于循环中令r=i
左边 = q[i] + 2*(q[i-1]+q[i]) //定义
右边w[i][i] = q[i-1]+p[i]+q[i]
所以得到E[i][i-1]+E[i+1][i] = q[i-1]+q[i]
有了上面的思路,我们就可以从一个结点出发,慢慢地扩充,每一步的扩充都基于之前更少结点的W和E,这种扩充方式有点类似于矩阵连乘问题的最小乘法次数
#include <iostream>#include <limits>#define N 5using namespace std;void BST(double q[], double p[], double w[][N+1], double e[][N+1], int root[][N+1]) { //将w[i][i-1], e[i][i-1]初始化 for (int i = 1; i <= N+1; i++) { w[i][i-1] = q[i-1]; //保证在求w[i][i]的时候q[i-1]+p[i]+q[i]=w[i][i] = w[i][i-1]+p[i]+q[i] e[i][i-1] = q[i-1]; //当r选择i或j作为根的时候,虽然左子树或右子树不包含关键字,但是依然包含虚拟键di-1和dj //对应到这边就是e[i][i-1]=q[i-1]以及e[j+1][j] = q[j];可以自己模拟试试就可以很轻松地发现这个规律 } for (int num = 1; num <= N; num++) {// d表示当前循环求几个结点构成的二叉树的最小代价 for (int i = 1; i <= N-num+1; i++) { int j = i+num-1; // 表示当前有num个结点参与 //搜索最小的e[i][j] e[i][j] = INT_MAX; w[i][j] = w[i][j-1] + p[j] + q[j]; for (int r = i; r <= j; r++) { double tmp = e[i][r-1] + e[r+1][j] + w[i][j]; if (tmp < e[i][j]) { e[i][j] = tmp; root[i][j] = r; } } } }}int main() { double p[N+1] = {0.00,0.15,0.10,0.05,0.10,0.20}; double q[N+1] = {0.05,0.10,0.05,0.05,0.05,0.10}; int root[N+1][N+1]; double w[N+1][N+1]; double e[N+1][N+1]; BST(q, p, w, e, root); for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { cout << root[i][j] << " "; } cout << endl; } return 0;}
- 最优二叉查找树的详细分析,c++代码实现
- 最优二叉查找树的Ruby实现
- 二叉查找树(二叉排序树)的详细实现C版
- 数据结构——二叉查找树的详细实现(c++)
- 构造最优二叉查找树的时间复杂度分析
- 构造最优二叉查找树的时间复杂度分析
- 二叉查找树C实现代码
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现 .
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现
- 二叉查找树(二叉排序树)的详细实现 .
- c#实现图片生成缩略图
- VS 2008研发驱动
- CGRectInset、CGRectOffset、frame和bounds对比
- c++ 高低位例子
- 软件方法过程考试点整理
- 最优二叉查找树的详细分析,c++代码实现
- Hibernate3
- Oracle中TO_DATE格式
- DRBD部署
- 使用JSP显示Jena解析结果
- freemarker学习总结
- MFC去掉单文档的"无标题-"的方法
- js获取height和width总结
- malloc/free VS new/delete