最优二叉查找树_动态规划

原问题是给出各个节点和各个节点的被查找概率,然后构造一棵各个节点平均被查找比较次数最小的树,则该问题可以用动态规划来解决

示例如下

推广到一般的情况,并设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求出,等我有空再把代码补上,用程序把树的构造描绘出来

原文地址:https://www.cnblogs.com/henuliulei/p/10074216.html

时间: 2024-10-18 02:28:10

最优二叉查找树_动态规划的相关文章

算法导论之动态规划(最长公共子序列和最优二叉查找树)

动态规划师通过组合子问题的解而解决整个问题,将问题划分成子问题,递归地求解各子问题,然后合并子问题的解而得到原问题的解.和分治算法思想一致,不同的是分治算法适合独立的子问题,而对于非独立的子问题,即各子问题中包含公共的子子问题,若采用分治法会重复求解,动态规划将子问题结果保存在一张表中,避免重复子问题重复求解. 动态规划在多值中选择一个最优解,其算法设计一般分为4个步骤:描述最优解的结构:递归定义最优解的值:按自底向上的方式计算最优解的值:由计算出的结果构造一个最优解. 1)装配线调度 求解最快

[CLRS][CH 15.5]最优二叉查找树

背景铺垫 假设我们正在设计一个翻译程序,讲英语翻译成法语,需要用一棵BST存储文章中出现的单词及等价的法语.因为要频繁地查找这棵树,所以我们希望查找时间越短越好.当然我们可以考虑使用红黑树,或者可能更适用的伸展树,来实现这一操作.但是这仍然不能满足我们的需要:由于单词出现频率不同,如果mycophagist这种奇怪的单词出现在根节点,而the.a.is这些常用单词出现在叶节点,即使O(lgn)的查找速度也极大的浪费了时间. 因此我们需要这样一种BST:频繁出现的单词出现在离根节点较近的地方.假设

【算法设计与分析基础】22、最优二叉查找树

package cn.xf.algorithm.ch08DynamicProgramming; import java.util.Arrays; import org.junit.Test; import cn.xf.algorithm.ch08DynamicProgramming.vo.ResultVo; /** * 最优二叉树问题 * * 思路:根据最优二叉树的问题就是查找对应的节点的比较次数的期望值保持最小 * 最优二叉查找树的期望搜索代价保持最小 * 例如:一颗树有节点{k0,k1,k2

算法第一讲_动态规划

转自follow your hearthttp://www.cnblogs.com/kkgreen/archive/2011/06/26/2090702.html 转载:http://blog.csdn.net/woshioosm/article/details/7438834{思考动态规划的第一点----最优子结构思考动态规划的第二点----子问题重叠思考动态规划的第三点----边界思考动态规划的第四点----子问题独立思考动态规划的第五点----做备忘录思考动态规划的第六点----时间分析步

算法导论_第十六章_动态规划_creatshare分享会

动态规划 注:该篇为本人原创,转载请注明出处:http://blog.csdn.net/chudongfang2015/article/details/51590817--开心 -.- 个人对动态规划的理解: 1.动态规划是一个付出额外空间来节省时间,就是所谓的空间换时间. 2.动态规划储存每个状态的最优解. 3.动态规划是用来把子问题的结果储存下来,再次用到的时候就不必再进行重复计算. 算法导论对动态规划的解释: 动态规划和分治方法相似,都是通过组合子问题的解来求解原问题,分治方法将问题划分为

算法导论_动态规划_最长公共子序列

一.动态规划的概念 动态规划(Dynamic Programming)是通过组合子问题的解而解决整个问题的.分治是指将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原始问题的解,与此不同,动态规划适用于子问题不是独立的情况,也就是各个子问题包含公共的子问题.在这种情况下,采用分治法会做许多不必要的工作,即重复地求解公共地子问题.动态规划算法对每个子问题只求解一次,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案. 动态规划通常应用于最优化问题.此类问题可

矩阵连乘问题_动态规划

1)问题引导 从上面我们可以知道不同的结合方式,矩阵计算的次序数不一样,那么如何求这个最小次序数的划分,即如何结合.这就是矩阵连乘问题 使用动态规划可以解决 如下图,如果我们使用递归,则会产生大量的重复计算,复杂度太高,当然使用备忘录降低复杂度.不过更好的是使用递推 递推算法分析如下: 1 #include<bits/stdc++.h> 2 using namespace std; 3 void matrixChain(int n,int p[],int m[][100],int s[][10

二叉查找树 _ 二叉排序树 _ 二叉搜索树_C++

一.数据结构背景+代码变量介绍 二叉查找树,又名二叉排序树,亦名二叉搜索树 它满足以下定义: 1.任意节点的子树又是一颗二叉查找树,且左子树的每个节点均小于该节点,右子树的每个节点均大于该节点. 2.由1可推出,任意节点的左孩子小于该节点,右孩子大于该节点 以上讨论的是左(右)孩子(子树)存在的情况 它的中序遍历是一个升序的排序 在参考代码中,我们定义有: 主程序中,k代表插入或删除或查找的节点的值 root,根节点位置:a[i],第 i 号节点的值:cl[i],第 i 号节点左孩子的位置:cr

MySQL调优系列_日志分析

技术准备 宿主于Ubuntu14.04.2平台下,基于MYSQL5.5.46版本. 日志文件记录了MySQL数据库的各种类型的活动,作为日常定位问题的最常用的一种分析手段,Mysql数据库中常用的日志文件分为以下几类:错误日志.二进制日志.慢查询日志,查询日志. 一.错误日志 该日志记录了MySQL运行过程中启动.运行.关闭过程中的一些详细记录,在一旦出现问题的时候,可以先查看该日志,该日志不但记录了出错信息,同样也记录了一些警告,当然也有一些运行信息. 可以通过如下命令,来查看错误日志的文件路