算法:最优二叉搜索树
算法设计第五次作业part2
1.纸面题:对最优二叉树和矩阵连乘两种算法验证四边形法则,如果符合四边形法则则举几个正例,如果不符合则举几个反例
四边形法则
i<i‘j<j‘w(i,j)+w(i‘,j‘)≤w(i‘,j)+w(i,j‘)i < i^`\ \ \ j < j^` \\ w(i,j) + w(i^`,j^`) \le w(i^`,j) + w(i,j^`) i<i‘ j<j‘w(i,j)+w(i‘,j‘)≤w(i‘,j)+w(i,j‘)
最优二叉树
符合四边形法则,举正例
对于如下输入
节点概率表
节点 | p1 | p2 | p3 | p4 | p5 |
---|---|---|---|---|---|
概率 | 0.15 | 0.10 | 0.05 | 0.10 | 0.20 |
伪节点概率表
节点 | (-无穷, p1) | (p1,p2) | (p2,p3) | (p3,p4) | (p4,p5) | (p5, 无穷) |
---|---|---|---|---|---|---|
概率 | 0.05 | 0.1 | 0.05 | 0.05 | 0.05 | 0.1 |
根据最优二叉搜索树算法,可以得出如下的二维矩阵e[i][j]
:
e[i][j]
表示包含关键字ki ... kj
的最优二叉搜索树进行一次搜索的期望代价,最终希望计算出 e[0][n]
:
0.05 | 0.45 | 0.90 | 1.25 | 1.75 | 2.75 |
---|---|---|---|---|---|
0 | 0.10 | 0.40 | 0.70 | 1.20 | 2.00 |
0 | 0 | 0.05 | 0.25 | 0.60 | 1.30 |
0 | 0 | 0 | 0.05 | 0.30 | 0.90 |
0 | 0 | 0 | 0 | 0.05 | 0.05 |
0 | 0 | 0 | 0 | 0 | 0.10 |
可以看到:
e[0][4]+e[1][5]≤e[0][5]+e[1][4]1.75+2.00≤1.20+2.75e[0][4] + e[1][5] \le e[0][5] + e[1][4]\\ 1.75 + 2.00 \le 1.20 + 2.75 e[0][4]+e[1][5]≤e[0][5]+e[1][4]1.75+2.00≤1.20+2.75
矩阵中其他非0元素,皆满足:
e[i][j]+e[i‘][j‘]≤e[i][j‘]+e[i‘][j]e[i][j] + e[i^`][j^`] \le e[i][j^`] + e[i^`][j] e[i][j]+e[i‘][j‘]≤e[i][j‘]+e[i‘][j]
则满足四边形法则
矩阵连乘
不满足,则举反例
现有如下矩阵列表:
A1 | A2 | A3 | A4 | A5 | A6 |
---|---|---|---|---|---|
30X35 | 35X15 | 15X5 | 5X10 | 10X20 | 2025 |
根据矩阵练乘动态规划算法,可以得出如下的备忘录m[i][j]
:
0 | 15750 | 7875 | 9375 | 11875 | 15125 |
---|---|---|---|---|---|
0 | 2625 | 4375 | 7125 | 10500 | |
0 | 750 | 2500 | 5375 | ||
0 | 1000 | 3500 | |||
0 | 5000 | ||||
0 |
其中可以看到:
m[0][2]+m[1][3]=7875+4375=12250m[1][2]+m[0][3]=2625+9375=12000m[0][2] + m[1][3] = 7875 + 4375 = 12250\\ m[1][2] + m[0][3] = 2625 + 9375 = 12000\\ m[0][2]+m[1][3]=7875+4375=12250m[1][2]+m[0][3]=2625+9375=12000
即:
m[0][2]+m[1][3]>m[1][2]+m[0][3]m[0][2] + m[1][3] > m[1][2] + m[0][3] m[0][2]+m[1][3]>m[1][2]+m[0][3]
不符合四边形法则的不等式定义。
2.编程实现最优二叉搜索树,输入输出自己定义。
package mainimport ("fmt""math"
)/**
编程实现最优二叉搜索树,输入输出自己定义
*/// 节点
type BSTNode struct {name string // 节点名left, right *BSTNode
}// 创建二维数组
func makeFloat2DimensionArray(row, column int) [][]float64 {result := make([][]float64, row)for i := 0; i < row; i++ {temp := make([]float64, column)result[i] = append(result[i], temp...)}return result
}
func makeInt2DimensionArray(row, column int) [][]int {result := make([][]int, row)for i := 0; i < row; i++ {temp := make([]int, column)result[i] = append(result[i], temp...)}return result
}func optimalBST(pList, qList []float64, n int) ([][]float64, [][]int) {// e[i,j] 表示包含关键字 ki ... kj 的最优二叉搜索树进行一次搜索的期望代价,最终希望计算出 e[1,n]e := makeFloat2DimensionArray(n+2, n+1)// w[i,j] 表示对于包含关键字 ki ... kj 的子树,所有的概率之和w := makeFloat2DimensionArray(n+2, n+1)// root[i,j] 表示包含关键字 ki ... kj 的子树的根root := makeInt2DimensionArray(n+1, n+1)for i := 1; i <= n+1; i++ {e[i][i-1] = qList[i-1]w[i][i-1] = qList[i-1]}for l := 1; l <= n; l++ {for i := 1; i <= n-l+1; i++ {j := i + l - 1e[i][j] = math.MaxFloat64w[i][j] = w[i][j-1] + pList[j] + qList[j]// 算法改进:动态规划加速if i < j {for r := root[i][j-1]; r <= root[i+1][j]; r++ {t := e[i][r-1] + e[r+1][j] + w[i][j]if t < e[i][j] {e[i][j] = troot[i][j] = r}}} else {e[i][j] = e[i][j-1] + e[i+1][j] + w[i][j]root[i][j] = i}}}return e, root
}// 打印 最优二叉搜索树
func makeBST(i, j int, root [][]int) {fmt.Printf("p%d 为 根\n", root[i][j])printBST(i, j, root)
}func printBST(i, j int, root [][]int) {if i <= j {r := root[i][j]if r > i {c := root[i][r-1]fmt.Printf("p%d 为 p%d 的左孩子\n", c, r)printBST(i, r-1, root)} else {fmt.Printf("q%d 为 p%d 的左孩子\n", r-1, r)}if r < j {c := root[r+1][j]fmt.Printf("p%d 为 p%d 的右孩子\n", c, r)printBST(r+1, j, root)} else {fmt.Printf("q%d 为 p%d 的左孩子\n", r+1, r)}}
}func main() {// 节点概率 0 表示无此节点pList := []float64{0, 0.15, 0.10, 0.05, 0.10, 0.20}// 区间概率qList := []float64{0.05, 0.1, 0.05, 0.05, 0.05, 0.1}e, root := optimalBST(pList, qList, 5)fmt.Printf("最优二叉搜索树总概率:%.2f \n", e[1][5])makeBST(1, 5, root)
}
输入
节点概率表
节点 | p1 | p2 | p3 | p4 | p5 |
---|---|---|---|---|---|
概率 | 0.15 | 0.10 | 0.05 | 0.10 | 0.20 |
伪节点概率表
节点 | (-无穷, p1) | (p1,p2) | (p2,p3) | (p3,p4) | (p4,p5) | (p5, 无穷) |
---|---|---|---|---|---|---|
概率 | 0.05 | 0.1 | 0.05 | 0.05 | 0.05 | 0.1 |
输出
总结
该算法为典型的动态规划算法,其中包含多个表进行递推。
e[i][j]
表示包含节点k1 ... kj
所组成的最优二叉搜索树进行一次搜索的期望,最终需要得到e[1][n]
w[i][j]
表示包含节点k1 ... kj
的概率之和root[i][j]
表示包含节点k1 ... kj
所组成的最优二叉搜索树的根
则可以列出关于 e[i][j]
的递推式和边界条件:
e[i][j]={qi−1(j=i−1)mini≤r≤j(e[i,r−1]+e[r+1][j]+w[i,j])(i≤j)e[i][j] = \begin{cases} q_{i-1} \ \ (j = i -1)\\ min_{i \le r \le j}(e[i,r-1]+e[r+1][j]+w[i,j]) \ \ (i \le j) \end{cases} \\ e[i][j]={qi−1 (j=i−1)mini≤r≤j(e[i,r−1]+e[r+1][j]+w[i,j]) (i≤j)
其中边界条件指,子树只包含伪关键字q[i-1]
;递推式则表示,当以 r 为根节点时,求出最小的期望值e[i][j]
;
而递推式的推导过程如下:
当将左右子树分别连接根节点 r 后,其概率都根据深度+1 而翻倍,即添加对应的w[i][j]
,则可根据定义得:
e[i][j]=pr+(e[i][r−1]+w[i][r−1])+(e[r+1][j]+w[r+1][j])其中(e[i][r−1]+w[i][r−1])为左子树,(e[r+1][j]+w[r+1][j])为右子树e[i][j] = p_r + (e[i][r-1] + w[i][r-1]) + (e[r+1][j] + w[r+1][j])\\ 其中(e[i][r-1] + w[i][r-1]) 为左子树,(e[r+1][j] + w[r+1][j])为右子树 e[i][j]=pr+(e[i][r−1]+w[i][r−1])+(e[r+1][j]+w[r+1][j])其中(e[i][r−1]+w[i][r−1])为左子树,(e[r+1][j]+w[r+1][j])为右子树
而:
w[i][j]=pr+w[i][r−1]+w[r+1][j]w[i][j] = p_r + w[i][r-1] + w[r+1][j] w[i][j]=pr+w[i][r−1]+w[r+1][j]
故可以化简得:
e[i][j]=e[i][r−1]+e[r+1][j]+w[i][j]e[i][j] = e[i][r-1] + e[r+1][j] + w[i][j] e[i][j]=e[i][r−1]+e[r+1][j]+w[i][j]
类似得,可以得出关于 w[i][j]
的递推式:
w[i][j]={qi−1(j=i−1)w[i][j−1]+p[j]+q[j](i≤j)w[i][j] = \begin{cases} q_{i-1} \ \ (j = i -1)\\ w[i][j-1] + p[j] + q[j] \ \ (i \le j) \end{cases} w[i][j]={qi−1 (j=i−1)w[i][j−1]+p[j]+q[j] (i≤j)
而root[i][j]
则与概率计算无关,主要用于回头构造二叉树时所用。
算法:最优二叉搜索树相关推荐
- 最优二叉搜索树(Optimal BST)-算法导论
问题描述: 维基百科定义: https://en.wikipedia.org/wiki/Optimal_binary_search_tree In the static optimality prob ...
- 算法导论 — 15.5 最优二叉搜索树
###笔记 二叉搜索树满足如下性质:假设xxx是二叉搜索树中的一个结点.如果lll是xxx的左子树的一个结点,那么l.key≤x.keyl.key ≤ x.keyl.key≤x.key.如果rrr是x ...
- 《算法导论》15.5 最优二叉搜索树(含C++代码)
一.问题背景和描述 给定一个n个不同关键字的已排序的序列K=<k1,k2, - kn>(因此k1<k2<-<kn),我们希望用这 些关键字构造一棵二叉搜索树.对每个关键字 ...
- 【算法设计与分析】动态规划:最优二叉搜索树
最优二叉搜索树问题的问题提出是,设S={x1, x2, -, xn}是一个由n个关键字组成的线性有序集,(a0, b1, a1, -, bn, an) 为集合S的存取概率分布,表示有序集S的二叉搜索树 ...
- 动态规划最优二叉搜索树C语言,算法 – 动态规划:最优二叉搜索树
好吧,我希望有人可以向我解释一下.我正在攻读决赛,我无法解决问题. 问题是动态编程;构造最优二叉搜索树(OBST).我理解一般的动态编程和特别是这个问题的概念,但我不明白这个问题的递归形式. 我得到的 ...
- 算法实验 最优二叉搜索树
最优二叉搜索树 最优二叉搜索树 问题描述 问题分析 代码 问题描述 二叉搜索树我们都知道,左子树结点的值都小于根结点,右子树结点的值都大于根节点.如果某个结点没有左子树或右子树,那么在对应的位置上加一 ...
- 动态规划最优二叉搜索树C语言,【算法导论】动态规划之“最优二叉搜索树”...
详解动态规划之"最优二叉搜索树" 之前两篇分别讲了动态规划的"钢管切割"和"矩阵链乘法",感觉到了这一篇,也可以算是收官之作了.其实根据前两 ...
- 算法设计与分析--最优二叉搜索树(Python)
最优二叉搜索树: 给定一个n个不同关键字的已排序的序列K=<k1,k2,-,kn>(因此k1<k2<-<kn)我们希望用这些关键字构造一棵二叉树.对每个关键字ki,都有一 ...
- 最优二叉搜索树探究【C/C++】
简述 什么是二叉树 下面的这棵树,就是二叉搜索树 相对于什么最优 这里考虑的是ASL(average search length)平均搜索长度.即根据概率来生成ASL最小的搜索树. 到这里,最优二叉搜 ...
最新文章
- VS Code – No source control providers 解决方法
- VC++ CopyFile函数使用方法
- 杭电1867 A + B for you again
- 设置UserAgent让电脑浏览器访问微信手机网站
- java 传入参数_Java 中方法参数的传递
- spark中各种数量的确定和查询(持续更新中)
- 单路电压表c语言编程,用AT89C51单片机制作的数字电压表
- python:对list去重
- html5白话解释,HTML5这个词到底是什么意思?
- 程序架构探讨—001 多段select语句的方案
- bazel 链接第三方动态库_C/C++编程知识:Linux 动态库相关知识整理
- 考研数据结构之栈(2.5)——练习题之求解二次方根A的迭代函数,写出相应的递归算法和非递归算法(C表示)
- C++ Primer Message和Folder类
- 鼠标悬停放大图片特效
- 象棋巫师魔法学校/象棋路边摊 前1050关
- “工程化”对于大型数据平台而言,意味着什么?StartDT Hackathon来了
- 【luminate primordial】苏州之行
- AI:华为云HiLens Kit试用测评—全栈全场景的人工智能
- 超市结算系统|Springboot+Vue通用超市结算收银系统
- 从小镇到北大!再到阿里达摩院,「AI萝莉」的“升级打怪”之路...
热门文章
- 火猫tv直播精灵 v1.1.1 官方版​
- excel如何一键多姿势
- python 进行图片的文字识别
- 16.div+css实战五 阿里云src响应中心底部制作
- 数据集2020(一)GraspNet-1Billion: A Large-Scale Benchmark for General Object Grasping
- 【LeetCode】树的子结构二叉树的镜像对称的二叉树
- 安装系统之四 U盘装GHOST XP教程
- 浪花淘尽英雄 --《浪潮之巅》读书笔记壹
- 登录验证过程,PC与APP开放登录接口(支持WEB与SDK方式)
- 联咏NT9833xSDK编译