最优二叉搜索树动态规划
2015-11-21 18:42
459 查看
问题描述:
最优二叉搜索树问题是对于有序集S及其存取概率或权值(q0,p1,q1,p2,q2,p3,q3),在所有表示有序集S的二叉搜索树中找出一颗具有最小平均路长的二叉搜索树。解决方法:
使用动态规划方法自底向上逐步构造最优二叉搜索树。
动态规划的两个重要要素是:
1、最优子结构。2、重叠子问题。
1)所谓最优化子结构是说若问题的一个最优解中包含了子问题的最优解,则该问题具有最优子结构。
2)重叠子问题,是指在递归解决方案中,若产生了大量的相同子问题,那么相同的子问题就会被重复计算很多次,这样算法的效率损耗就很大。
问题中,q0,q1,q2,q3为外部节点,即搜索不成功的权值或概率,p1,p2,p3为内部节点,即搜索成功的权值或概率,T[i][j]为一颗从i到j的子树,w[i][j]来存放累计权值,c[i][j]为一颗树的代价,r[i][j]存放一棵树的根。
<1>、算法思路:
(1)、构造只有一个内部节点的最优二叉搜索树:
c[i-1][j]=w[i-1][i]
r[i-1][i]=i
(2)、构造具有m(m>=2)个内部节点的最优二查搜索树:
c[i][j]=w[i][j]+min{c[i][k-1]+c[k][j]},i<k<=j
r[i][j]=k,i<k<=j
<2>、算法代码:
#include<iostream> using namespace std; const int n = 3; int r[n+1][n+1];//存放各最优二叉树搜索树的根 int c[n+1][n+1];//最优二查搜索树的代价(最小平均路长) int w[n+1][n+1];//存放内部节点外部节点的累计权值 void OBST(int *p,int *q,int n); void printOBST(int r[n+1][n+1],int i,int j,int n,int f,char ch); int main() { int p[]={0,5,10,50};//内部节点的权值 int q[]={15,10,5,5};//外部节点的权值 cout<<"内部节点的权值为:"<<endl; for(int i=1;i<n+1;i++)//输出内部节点的权值 { cout<<"p"<<i<<"="<<p[i]<<endl; } cout<<"外部节点的权值为:"<<endl; for(int j=0;j<n+1;j++)//输出外部节点的权值 { cout<<"q"<<j<<"="<<q[j]<<endl; } cout<<endl; OBST(p,q,n); cout<<"最优二叉搜索树的最小平均路长为:"<<c[0] <<endl; cout<<"构造的最优二叉搜索树为:"<<endl;//输出最优二叉树搜索树各个子树的根 printOBST(r,0,n,n,0,'0'); system("pause"); return 0; } void OBST(int *p,int *q,int n)//自底向上逐步构造w[][],c[][],r[][] { int i,j,k,m,min,u; for(i=0;i<n;i++){ //初始化 w[i][i]=q[i]; c[i][i]=r[i][i]=0; //构造只有一个内部节点的最优二查搜索树 w[i][i+1]=w[i][i]+p[i+1]+q[i+1]; r[i][i+1]=i+1; c[i][i+1]=w[i][i+1]; } w =q ; r =c =0; for(m=2;m<=n;m++)//构造具有m个内部节点的最优二查搜索树 { for(i=0;i<=n-m;i++){ //在前一颗树的基础上加以内部节点和一外部节点 //分别构造具有m,m+1...n个内部节点的最优二查搜索树 j=i+m; w[i][j]=w[i][j-1]+p[j]+q[j];//构造出从i到j的累计权值 min=c[i+1][j]; u=i+1;//假定i+1为根 for(k=i+2;k<=j;k++)//轮流以i+2,i+3...j为根,选代价最小的送min,其根为u { if(c[i][k-1]+c[k][j]<min) { min=c[i][k-1]+c[k][j]; u=k; } } c[i][j]=w[i][j]+min; r[i][j]=u; } } } void printOBST(int r[n+1][n+1],int i,int j,int n,int f,char ch) { int k=r[i][j]; if(k>0) { if(f==0) { cout<<"T("<<i<<","<<j<<")"<<"的根节点为:"<<k<<endl; } else { cout<<ch<<"子树:"<<"T("<<i<<","<<j<<")"<<"的根节点为:"<<k<<endl; } int t=k-1; if(t>=i && t<=n) { printOBST(r,i,t,n,k,'L');//递归输出左子树的根节点 } int m=k+1; if(t<=j) { printOBST(r,m-1,j,n,k,'R');//递归输出右子树的根节点 } } }
相关文章推荐
- Web框架对比: Wicket vs Struts
- Spark分布式环境搭建
- 1 认识Jquery
- 单消息队列客户-服务器间的双向通信
- GDB+GDBServer安装
- 项目4 - 利用遍历思想求解图问题(6-7)
- 浅谈二叉树遍历的栈方法
- Jenkins邮件模板
- 项目4 - 利用遍历思想求解图问题(1-5)
- Java——用户名输入框
- 闪屏页面开发遇到的问题you need to use a theme.appcompat theme (or descendant)
- 闪屏页面开发遇到的问题you need to use a theme.appcompat theme (or descendant)
- IOS通过数组给Cell中的文本框和小图标赋值
- 闪屏页面开发遇到的问题you need to use a theme.appcompat theme (or descendant)
- 类库/框架/SDK
- 设置了Media.EXTERNAL_CONTENT_URI却找不到音频/视频的解决方法
- C++学习笔记27——泛型算法之统计(accumate count)
- iOS开发中同时识别旋转与缩放手势
- path与classpath区别,内存管理
- 项目5 - 迷宫问题之图深度优先遍历解法