最优二叉查找树(动态规划)
2012-09-08 21:56
288 查看
1. 描述
给定一个有序序列K={k1<k2<k3<,……,<kn}和他们被查询的概率P={p1,p2,p3,……,pn},要求构造一棵二叉查找树T,使得查询所有元素的总的代价最小。对于一个搜索树,当搜索的元素在树内时,表示搜索成功。当不在树内时,表示搜索失败,用一个“虚叶子节点”来表示搜索失败的情况,因此需要n+1个虚叶子节点{d0<d1<……<dn}。其中d0表示搜索元素小于k1的失败结果,dn表示搜索元素大于kn的失败结果。di(0<i<n)表示搜索节点在ki和k(i+1)之间时的失败情况。对于应di的概率序列是Q={q0,q1,……,qn}。
2. 分析
(1)最优子结构
一个最优二叉树的子树必定包含连续范围的关键字ki~kj,1 <= i <= j<= n,同时也必须含有连续的虚叶子节点di-1~dj。
如果一棵最优二叉查找树T有一棵含有关键字ki~kj的子树T',那么,T'也是一棵最优查找树,这通过剪贴思想可以证明。
构造最优子结构:在ki~kj中,选定一个r,i <= r <= j,使以kr为根,ki~k(r-1)和k(r+1)~kj为左右孩子的最优二叉树。注意r=i或者r=j的情况,表示左子树或右子树只有虚叶子节点。
(2)递推公式
定义e[i,j]为一棵包含关键字ki~kj的最优二叉树的期望代价。当j=i-1时没有真实的关键在,只有虚叶子节点d(i-1)。
则:
e[i,i-1] = q(i-1)
j = i-1时,
当j >= i时,需要选择合适的kr作为根节点,然后其余节点ki~K(r-1)和k(r+1)~kj构造左右孩子。这时要考虑左右孩子这些节点成为一个节点的子树后,它的搜索代价的变化:它们的期望代价增加了“子树中所有概率的总和”w。
w[i,j] = (pi + ... + pj) + (qi-1 + ... + qj)
于是当 j>= i时,e[i,j]=pr + (e[i,r-1]+w[i,r-1])+(e[r+1,j]+w[r+1,j]) = e[i,r-1] +e[r+1,j]+w[i,j];
(3)计算最优二叉树的期望代价
e[i,j]=
q(i-1) j = i-1时
min{e[i,r-1] +e[r+1,j]+w[i,j]} i <= j,其中i <= r <= j
w[i,j] =
q(i-1) j = i-1时
w[i,j]=w[i,j-1]+pj+qj i <= j时
3. 算法
算法如下:
root是记录构造过程中选择的根节点,以便构造最优解。
constructOptimalBST函数如下:
其中recursiveConstruct函数如下:
测试如下:
输出:
给定一个有序序列K={k1<k2<k3<,……,<kn}和他们被查询的概率P={p1,p2,p3,……,pn},要求构造一棵二叉查找树T,使得查询所有元素的总的代价最小。对于一个搜索树,当搜索的元素在树内时,表示搜索成功。当不在树内时,表示搜索失败,用一个“虚叶子节点”来表示搜索失败的情况,因此需要n+1个虚叶子节点{d0<d1<……<dn}。其中d0表示搜索元素小于k1的失败结果,dn表示搜索元素大于kn的失败结果。di(0<i<n)表示搜索节点在ki和k(i+1)之间时的失败情况。对于应di的概率序列是Q={q0,q1,……,qn}。
2. 分析
(1)最优子结构
一个最优二叉树的子树必定包含连续范围的关键字ki~kj,1 <= i <= j<= n,同时也必须含有连续的虚叶子节点di-1~dj。
如果一棵最优二叉查找树T有一棵含有关键字ki~kj的子树T',那么,T'也是一棵最优查找树,这通过剪贴思想可以证明。
构造最优子结构:在ki~kj中,选定一个r,i <= r <= j,使以kr为根,ki~k(r-1)和k(r+1)~kj为左右孩子的最优二叉树。注意r=i或者r=j的情况,表示左子树或右子树只有虚叶子节点。
(2)递推公式
定义e[i,j]为一棵包含关键字ki~kj的最优二叉树的期望代价。当j=i-1时没有真实的关键在,只有虚叶子节点d(i-1)。
则:
e[i,i-1] = q(i-1)
j = i-1时,
当j >= i时,需要选择合适的kr作为根节点,然后其余节点ki~K(r-1)和k(r+1)~kj构造左右孩子。这时要考虑左右孩子这些节点成为一个节点的子树后,它的搜索代价的变化:它们的期望代价增加了“子树中所有概率的总和”w。
w[i,j] = (pi + ... + pj) + (qi-1 + ... + qj)
于是当 j>= i时,e[i,j]=pr + (e[i,r-1]+w[i,r-1])+(e[r+1,j]+w[r+1,j]) = e[i,r-1] +e[r+1,j]+w[i,j];
(3)计算最优二叉树的期望代价
e[i,j]=
q(i-1) j = i-1时
min{e[i,r-1] +e[r+1,j]+w[i,j]} i <= j,其中i <= r <= j
w[i,j] =
q(i-1) j = i-1时
w[i,j]=w[i,j-1]+pj+qj i <= j时
3. 算法
算法如下:
void optimalBST(int n, float p[], float q[]) // the length of p and q is (n + 1) { float w[n + 2][n + 1], e[n + 2][n + 1], temp; int root[n + 1][n + 1]; int i, j, l, r; for (i = 1;i <= n + 1; i++) w[i][i - 1] = e[i][i - 1] = q[i - 1]; for (l = 1; l <= n; l++) for (i = 1, j = l; i <= n - l + 1; i++, j++) { e[i][j] = INT_MAX; w[i][j] = w[i][j - 1] + p[j] + q[j]; for (r = i; r <= j; r++) { temp = e[i][r - 1] + e[r + 1][j] + w[i][j]; if (e[i][j] > temp) { e[i][j] = temp; root[i][j] = r; } }// for (r = i; ) }// for printf("The optimal search cost is %.2f\n", e[1] ); constructOptimalBST(n, root); }
root是记录构造过程中选择的根节点,以便构造最优解。
constructOptimalBST函数如下:
void constructOptimalBST(int n, int root[][n + 1]) { printf("k%d is the root\n", root[1] ); recursiveConstruct(n, root, root[1] , 1, n); }
其中recursiveConstruct函数如下:
void recursiveConstruct(int n, int root[][n + 1], int r, int i, int j) { if (j == i - 1) { if (i == r) printf("d%d is the left child of k%d\n", r - 1, r); else printf("d%d is the right child of k%d\n", r, r); } else { if (i != r) { printf("k%d is the left child of k%d\n", root[i][r - 1], r); recursiveConstruct(n, root, root[i][r - 1], i, r - 1); } else{ printf("d%d is the left child of k%d\n", r - 1, r); if (j != r) { printf("k%d is the right child of k%d\n", root[r + 1][j], r); recursiveConstruct(n, root, root[r + 1][j], r + 1, j); } else printf("d%d is the right child of k%d\n", r, r); } }
测试如下:
#include <stdio.h> #include <limits.h> void optimalBST(int n, float p[], float q[]); void constructOptimalBST(int n, int root[][n + 1]); void recursiveConstruct(int n, int root[][n + 1], int r, int i, int j); int main(void) { float p[] = {-1, 0.15, 0.10, 0.05, 0.10, 0.20}; float q[] = {0.05, 0.10, 0.05, 0.05, 0.05, 0.10}; int n = 5; optimalBST(n, p, q); return 0; }
输出:
相关文章推荐
- 算法导论 ch15 动态规划 最优二叉查找树
- 【算法学习】最优二叉查找树(动态规划)
- 数据结构之(动态规划)之最优二叉查找树
- 【算法导论】动态规划之最优二叉查找树
- 动态规划——最优二叉查找树
- 【算法学习】最优二叉查找树(动态规划)
- 【算法导论】动态规划之最优二叉查找树
- 最优二叉查找树的期望搜索代价(动态规划)C++实现
- 算法导论学习笔记(10)——动态规划之最优二叉查找树
- 【算法学习】最优二叉查找树(动态规划)
- 《算法导论》读书笔记之第15章 动态规划—最优二叉查找树
- 【算法学习】最优二叉查找树(动态规划)
- 用动态规划求最优二叉查找树
- 【算法学习】最优二叉查找树(动态规划)
- 最优二叉查找树(动态规划)
- 动态规划 -- 最优二叉查找树
- 动态规划--最优二叉查找树
- 最优二叉查找树的期望搜索代价(动态规划)C++实现
- 动态规划——最优二叉查找树
- 动态规划--最优二叉查找树(转载小妞滴。。。)