最优二叉搜索树探究【C/C++】
简述
什么是二叉树
下面的这棵树,就是二叉搜索树
相对于什么最优
这里考虑的是ASL(average search length)平均搜索长度。即根据概率来生成ASL最小的搜索树。
到这里,最优二叉搜索树的概念就已经清楚了。
解决方法
如果是递归来搜索也是可以的,但是很明显需要做很多的重复的计算。
为了解决这个问题,所以我们采用动态规划来做,很明显,这样能降低计算的复杂度。
- 处理方法:动态规划
在非叶节点上时候,为特定的数值,在叶子节点上时候,是一个区间(这里不懂可以再看上面的图)
显然,我们需要先用递归的方式来理解一下这个问题。
w[i][j] = a[i-1] + b[i] +.. + b[j] + a[j]
- 其中,
a[i]
表示的是第i个区间的概率,b[i]
表示的是第i个节点的概率 w[i][i] = a[i-1] + b[i] + a[i]
这不就是一个只有一个非叶子节点的二叉树么?- 如果是只有一个非叶子节点的二叉搜索树的话:我们这里很好求
- 进行扩展:我们现在只考虑这么的一棵树,中间点为具体数值,那么就是非叶子节点。然后根据这个节点(设为节点k)的进行推理
ASL[i][j] = b[k] * 1 + (ASL_Left_tree + 1) * W[i][k-1] + (ASL_Right_tree + 1) * W[k+1][j]
- 注意到,中间有部分可以提出来,得到
ASL[i][j] = W[i][j] + (ASL_Left_tree ) * W[i][k-1] + (ASL_Right_tree ) * W[k+1][j]
(这里W[i][j] = 1
) - 但是我们这里其实考虑的整棵数,对于更一般的,我们要考虑一个树的一部分。
ASL[i][j] = 1 + (ASL_Left_tree ) * W[i][k-1] + (ASL_Right_tree ) * W[k+1][j]
这是上面的整理。下面再接着推理。W[i][j] * ASL[i][j] = W[i][j] + (ASL_Left_tree ) * W[i][k-1] + (ASL_Right_tree ) * W[k+1][j]
注意,这里的W[i][j]
都是在全局的树上算的,因为这时候把左边的W[i][j]
就类似的得到的我们想要的条件概率下是计算算法。- 做类似的变换很容易发现,所谓左树和右树也是可以用
i,j
来表示的。然后,就得到一个很重要的 递推公式 W[i][j] * ASL[i][j] = W[i][j] + ASL[i][k-1] * W[i][k-1] + ASL[k+1][j] * W[k+1][j]
但是我们注意到这里的w[i][j] * ASL[i][j]
其实可以作为一个整体来计算的。这里就设置为M[i][j]
- 所以公式变为了
m[i][j] = w[i][j] + m[i][k-1] + m[k+1][j]
。注意到,我们这里是假设了采用的是以第k个点作为分割点来构建子树的。但是实际上这个最优的究竟该怎么搞,肯定是需要遍历所有的可能的k来得到结果的。 - 所以,其实
m[i][j] = w[i][j] + min(m[i][k-1] + m[k+1][j])
。但是我们这里需要注意到,我们想要的整棵数的ASL其实就是m[1][N]
,而此时的概率为1了,所以得到的相等。
边界条件讨论:
w[i+1][i]
这种情况究竟是算什么呢?我们这里设置为a[i]
m[i+1][i]
这种情况呢?我们令它为0。这样,我们在利用上面的公式推理出来的结果的时候,就得到了m[i][i] = w[i][i]
。- 至于它为0,其实很好证明,由于在
ASL[i+1][i]
肯定要是0才对的。
程序实现细节
主要是注意一下,实现的时候,如何安排数据。建议的话,将b的那个数组前面空出一个来,这样的话,就不需要修改太多的公式。
原因如下:
w[i][j] = a[i-1] + b[i] +.. + b[j] + a[j]
- 为了避免程序实现的时候越界。(否则就需要修改公式了,这里先可以先完成之后,再考虑优化的问题)
看到这,如果你有去手动实现的话,你会意识到另外一个问题。这个可行的k究竟是什么?
- 由于我们之前已经谈到了设置了时候,我们讲b的那个数组第一个位置放空,那么来说
i和j
都是从1开始遍历起的,终止当然就是以N
作为终止点。 - 知道上面的这些之后,我们就很容易理清了,我们尝试将i到j上的所有节点
C++代码
注释部分写好了详细的代码说明~
main函数开始部分是自动生成数据来进行测试
#include <iostream>
using namespace std;
#include <string>
#define N 15int S[N];
double b[N + 1];
double a[N + 1];
// w[i][j] 表示i,j段的概率
//
double w[N + 2][N + 2];
// w[i][j] = a[i-1] + b[i] +...+b[j] + a[j]
double m[N + 2][N + 2];
int divided_point[N + 1][N + 1];
string getAns(int begin, int end);
int main() {double sum = 0;for (int i = 0; i < N; ++i) {S[i] = 2 * i + 1;b[i+1] = 0.6 / (N+1);a[i] = 0.4 / (N+1);sum += (a[i] + b[i+1]);}b[0] = 0;a[N] = 1 - sum;/*for (int i = 0; i < N; ++i) {S[i] = 2 * i + 1;a[i + 1] = 0.04;b[i + 1] = 0.06;}a[0] = 0.1;b[0] = 0;*/// 初始化for (int i = 0; i <= N; ++i) {w[i + 1][i] = a[i];m[i + 1][i] = 0;// ASL[i][i-1]为0!}// r表示的是长度for (int r = 0; r < N; ++r)for (int i = 1; i <= N-r; i++) {// i表示的是起始点int j = i + r; // j表示的是终点// 由w[i][j]构造函数很容易得到w[i][j] = w[i][j - 1] + a[j] + b[j];m[i][j] = m[i + 1][j]; // 因为m[i][i-1]为0divided_point[i][j] = i;// 中间划分点设为b[i] k为滑动的移动点for (int k = i + 1; k <= j; k++) {double t = m[i][k - 1] + m[k + 1][j];if (t < m[i][j]) { m[i][j] = t; divided_point[i][j] = k;}}m[i][j] += w[i][j];}cout << m[1][N] << " " << w[1][N] << endl;system("pause");
}
最优二叉搜索树探究【C/C++】相关推荐
- 动态规划法实现最优二叉搜索树
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的 ...
- 最优二叉搜索树(Optimal BST)-算法导论
问题描述: 维基百科定义: https://en.wikipedia.org/wiki/Optimal_binary_search_tree In the static optimality prob ...
- pintia 7-25 最优二叉搜索树
pintia 7-25 最优二叉搜索树 输出格式: 第一行输出最小 m ,保留两位小数. 第二行先序遍历输出二叉树,对于实结点输出其编号,对于虚结点输出.,每一个符号后有一个空格,若有多个满足要求的二 ...
- 算法导论 — 15.5 最优二叉搜索树
###笔记 二叉搜索树满足如下性质:假设xxx是二叉搜索树中的一个结点.如果lll是xxx的左子树的一个结点,那么l.key≤x.keyl.key ≤ x.keyl.key≤x.key.如果rrr是x ...
- 算法:最优二叉搜索树
算法设计第五次作业part2 1.纸面题:对最优二叉树和矩阵连乘两种算法验证四边形法则,如果符合四边形法则则举几个正例,如果不符合则举几个反例 四边形法则 i<i'j<j'w(i,j)+w ...
- 算法实验 最优二叉搜索树
最优二叉搜索树 最优二叉搜索树 问题描述 问题分析 代码 问题描述 二叉搜索树我们都知道,左子树结点的值都小于根结点,右子树结点的值都大于根节点.如果某个结点没有左子树或右子树,那么在对应的位置上加一 ...
- 动态规划最优二叉搜索树C语言,【算法导论】动态规划之“最优二叉搜索树”...
详解动态规划之"最优二叉搜索树" 之前两篇分别讲了动态规划的"钢管切割"和"矩阵链乘法",感觉到了这一篇,也可以算是收官之作了.其实根据前两 ...
- 动态规划——最优二叉搜索树
(二叉搜索树即二叉排序树,该题并不是问如何构造最优二叉树,而是如何在二叉搜索树中达成最优搜索效率) 简而言之,这个最优二叉搜索树的每个根节点都大于左子树的任一元素,小于其右子树的任意元素,相当于用根 ...
- 最优二叉搜索树相关内容
01 最优二叉搜索树概念 设S={x1,x2,-,xn.}是有序集,且x1<x2<-<xn, 表示有序集S的二叉搜索树利用二叉树的结点来存储有序集中的元素.它具有下述性质:存储于每个 ...
最新文章
- AJAX学习基础:简单介绍数据岛使用方法
- linux常用shell命令面试,shell经典笔试题目总结
- [Android] 任意时刻从子线程切换到主线程的实现
- ASP中利用OWC控件实现图表功能详解[zz]
- mysql 多表查询 优化_Mysql 多表联合查询效率分析及优化
- jQuery图表开源软件
- 58 - 算法 - 百练 2503:Babelfish 二分查找与存储
- Oracle的分区表
- Docker使用Dockerfile创建Centos(tomcat+jdk)镜像
- Mac基础知识:在mac上怎么使用程序坞
- Mail: JMail, System.Net.Mail, System.Web.Mail
- 虚拟机中使linux系统分辨率变大
- 【Nowcoder - 5670 B Graph】2020 牛客暑期多校训练营(第五场)【最小异或生成树、Boruvka 思想】
- HotSpot虚拟机对象揭秘
- 潜在语义分析(TF-IDF、LSA)
- 小程序图片上传无反应
- php调查问卷数据库,关于一个问卷调查的程序,如何插入数据库
- 代码坏味道 之 9 基本类型偏执 primitive obsession
- soul服务器不稳定,soul聊天状态异常 消息发送失败
- 面试问到这个我直接蒙了,你呢?
热门文章
- 让Redis突破内存大小的限制
- 全局脚手架了解一下【fle-cli】
- 设置 Confluence 6 日志
- 前端论坛、博客及公众号汇总
- Mobile first! Wijmo 5 + Ionic Framework之:Hello World!
- 使用Spring Data Redis操作Redis(集群版)
- keepalived 主从配置日志报错:one or more vip associated with vrid mismatch actual master advert...
- sublime text 使用笔记
- 查看LINUX当前负载
- mysql修改默认编码为UTF8