简述

什么是二叉树

下面的这棵树,就是二叉搜索树

相对于什么最优

这里考虑的是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++】相关推荐

  1. 动态规划法实现最优二叉搜索树

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的 ...

  2. 最优二叉搜索树(Optimal BST)-算法导论

    问题描述: 维基百科定义: https://en.wikipedia.org/wiki/Optimal_binary_search_tree In the static optimality prob ...

  3. pintia 7-25 最优二叉搜索树

    pintia 7-25 最优二叉搜索树 输出格式: 第一行输出最小 m ,保留两位小数. 第二行先序遍历输出二叉树,对于实结点输出其编号,对于虚结点输出.,每一个符号后有一个空格,若有多个满足要求的二 ...

  4. 算法导论 — 15.5 最优二叉搜索树

    ###笔记 二叉搜索树满足如下性质:假设xxx是二叉搜索树中的一个结点.如果lll是xxx的左子树的一个结点,那么l.key≤x.keyl.key ≤ x.keyl.key≤x.key.如果rrr是x ...

  5. 算法:最优二叉搜索树

    算法设计第五次作业part2 1.纸面题:对最优二叉树和矩阵连乘两种算法验证四边形法则,如果符合四边形法则则举几个正例,如果不符合则举几个反例 四边形法则 i<i'j<j'w(i,j)+w ...

  6. 算法实验 最优二叉搜索树

    最优二叉搜索树 最优二叉搜索树 问题描述 问题分析 代码 问题描述 二叉搜索树我们都知道,左子树结点的值都小于根结点,右子树结点的值都大于根节点.如果某个结点没有左子树或右子树,那么在对应的位置上加一 ...

  7. 动态规划最优二叉搜索树C语言,【算法导论】动态规划之“最优二叉搜索树”...

    详解动态规划之"最优二叉搜索树" 之前两篇分别讲了动态规划的"钢管切割"和"矩阵链乘法",感觉到了这一篇,也可以算是收官之作了.其实根据前两 ...

  8. 动态规划——最优二叉搜索树

     (二叉搜索树即二叉排序树,该题并不是问如何构造最优二叉树,而是如何在二叉搜索树中达成最优搜索效率) 简而言之,这个最优二叉搜索树的每个根节点都大于左子树的任一元素,小于其右子树的任意元素,相当于用根 ...

  9. 最优二叉搜索树相关内容

    01 最优二叉搜索树概念 设S={x1,x2,-,xn.}是有序集,且x1<x2<-<xn, 表示有序集S的二叉搜索树利用二叉树的结点来存储有序集中的元素.它具有下述性质:存储于每个 ...

最新文章

  1. AJAX学习基础:简单介绍数据岛使用方法
  2. linux常用shell命令面试,shell经典笔试题目总结
  3. [Android] 任意时刻从子线程切换到主线程的实现
  4. ASP中利用OWC控件实现图表功能详解[zz]
  5. mysql 多表查询 优化_Mysql 多表联合查询效率分析及优化
  6. jQuery图表开源软件
  7. 58 - 算法 - 百练 2503:Babelfish 二分查找与存储
  8. Oracle的分区表
  9. Docker使用Dockerfile创建Centos(tomcat+jdk)镜像
  10. Mac基础知识:在mac上怎么使用程序坞
  11. Mail: JMail, System.Net.Mail, System.Web.Mail
  12. 虚拟机中使linux系统分辨率变大
  13. 【Nowcoder - 5670 B Graph】2020 牛客暑期多校训练营(第五场)【最小异或生成树、Boruvka 思想】
  14. HotSpot虚拟机对象揭秘
  15. 潜在语义分析(TF-IDF、LSA)
  16. 小程序图片上传无反应
  17. php调查问卷数据库,关于一个问卷调查的程序,如何插入数据库
  18. 代码坏味道 之 9 基本类型偏执 primitive obsession
  19. soul服务器不稳定,soul聊天状态异常 消息发送失败
  20. 面试问到这个我直接蒙了,你呢?

热门文章

  1. 让Redis突破内存大小的限制
  2. 全局脚手架了解一下【fle-cli】
  3. 设置 Confluence 6 日志
  4. 前端论坛、博客及公众号汇总
  5. Mobile first! Wijmo 5 + Ionic Framework之:Hello World!
  6. 使用Spring Data Redis操作Redis(集群版)
  7. keepalived 主从配置日志报错:one or more vip associated with vrid mismatch actual master advert...
  8. sublime text 使用笔记
  9. 查看LINUX当前负载
  10. mysql修改默认编码为UTF8