算法导论_15.5 最优二叉查找树

本文探讨了如何构建最优二叉查找树,用于英语到法语单词的快速搜索。考虑到单词出现频率,目标是降低翻译文章时的搜索成本。通过动态规划的方法,分析了树的期望代价,并提供了递归解法。文章还提出了优化搜索代价的算法思路,以减少时间复杂度。
摘要由CSDN通过智能技术生成

一、问题

将英文翻译成法语,使用平衡二叉树建立英语-法语单词的键值对,便于搜索;
文章中单词出现次数有频率,有些单词出现频繁, 有些单词出现概率很小;应当将频繁出现的单词放在距离根较近的地方;
此外,注意到有部分英语单词没有对应的法语翻译
访问一个结点的代价是:结点的深度+1;
我们已知英语文章中各类单词出现的频率,试图构造一棵最优二叉查找树,使得翻译文章的速度最快(访问的结点数最小);

假设有对应法语翻译的英语单词的深度是k[i], 其频率是p[i];
没有对应法语翻译的英语单词的深度是d[i], 其频率是q[i];
翻译整篇英语文章,搜索单词的代价是:
在这里插入图片描述
我们已知pi, qi; 对于不同的depth(ki) 和depth(di), 求出E的最小值;不同的二叉树结构,会得到不同的depth(ki) 和depth(di);

二、求解步骤

1) 一棵最优二叉查找树的结构

一个二叉查找树(i, j),其根节点是r, 这个二叉查找树具有最优化结构, 那么这个二叉查找树的左子树(i, r-1) 也具有最优化结构, 其右子树(r+
1, j)也具有最优化结构;
因为树(i, j)具有最优化结构(e(i, j)的值最小), 如果左子树不具有最优化结构,可以选用另外一个子树T’代替现有的左子树,但这会导致树e(i, j)的值变得更小,矛盾;
e(i, j) = e(i, r-1)+e(r+1, j)+w(i, r-1)+ w(r+1, j)+p®;
树的期望代价等于左子树的期望代价+右子树的期望代价, 由于左子树和右子树现在变为子树,其上的所有结点深度+1, 所以加上w(i, r-1) 和w(r+1, j); 再加上pr*1(根结点只要一次访问);
2) 一个递归解
e[i, i] 表示叶子节点的上一层的子树;
e[i, i] 的左子树是e[i, i-1]即d[i-1];
e[i, i] 的右子树是e[i+1, i], 即d[i];
叶子节点都是虚拟键,也是边界条件;
j = i-1的时候, 表示此时的英语单词没有对应的法语翻译;这也是边界条件;
在这里插入图片描述
其中w(i, j):
在这里插入图片描述
w(i, j) 是从i, 到j的期望,也就是概率之和,不管k的取值是多少, w(i, j) 是相同的;
所以取r=j时候的w(i, j) = w(i, j-1) + w(j+1, j) + pj = w(i, j-1) + qj + pj;
其中i<= r<= j:
当i == r的时候, e[i, r-1] = e[i, i-1], 其左子树是d(i-1), 右子树是e[i+1, j];(左子树是没有对应翻译的单词);
当i == j的时候, e[r+1, j] = e[j+1, j], 其右子树是dj;
举例说明动态规划的边界:

分析式子:
e(i, j) = e(i, r-1)+e(r+1, j)+w(i, r-1)+ w(r+1, j)+pr;
定义e(i, i-1) = q(i-1)
当i == j的时候,即e(i, i)代表什么,代表着以ki为根的树的期望代价
得到:
e(i, i) = e(i, i-1) + e(i+1, i) + w(i, i);
我们得到
e(1, 1) = e(1, 0) + e(2, 1) + w(1, 1) = q0+q1 +q0+q1+k1 = 0.45; //没有k0

在分析e(3, 4) = e(3, 3) + e(5, 4) + w(3, 4) = e(3, 3) + d4 + w(3, 4) //选择A
=e(3, 2)+e(4, 4) + w(3, 4) = d2 + e(4, 4) + w(3, 4) //选择B
这两个选择对应两种树的结构;在动态规划的过程中,不断的选择就相当于不断的比较不同的二叉树结构;
在这里插入图片描述
因此,关于最优二叉查找树中的边界问题,需要记住两个点:

  1. e(i, i-1)相当于q(i-1);
  2. 很难理解e(k, k)的含义,是一个根为k的树,但是这个树只有虚拟键;
    区分e(i, j)的树,其根是k; 这也是一个根为k的树,但是这个树有实键也有虚拟键;
    只有虚拟键的树e(k, k)在动态规划的选择过程中,经过左旋转或是右旋转, 变成了带有实键的树;例如, 上图中的k4子树, 一开始只有虚键值,选过过程中k4树将实键值k3变成自己的子树;

3) 计算一棵最优二叉查找树的期望搜索代价
给定一个n个互异的关键字组成的序列K = {k1, k2, …, Kn}, 这个序列单调递增,同时假设没有对应法语翻译的英语单词序列是n+1个元素的L = {d0, d1, d2, …, dn}

代码实现过程中, 通常分配n+1个数组存储序列K,并且使得k0 = -1;

使用二维数组e[i][j] 记录子树(i, j)的最小搜索代价;由于i, j的最大值是n+1, 所以二维数组e的维数是[n+2, n+2];
使用二维数组w[i][j] 记录子树(i, j) 由子问题构造过程中需要支付的代价,其维数也是[n+2, n+2];

#include <stdio.h>
#include <stdlib.h>

#define n 5

//不建议将这些数组变成自变量存放在栈中,在栈中的变量没有初始化,其值是不确定的
double e[n + 2][n + 2];
double w[n + 2][n + 2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值