使用备忘录方法求解最优二叉搜索树问题

问题描述

给定递增有序的元素序列 S = ⟨ a 1 , a 2 , ⋯   , a n ⟩ S=\left \langle a_1,a_2,\cdots,a_n\right \rangle S=a1,a2,,an与相关存取概率分布 C = ⟨ q ( 0 ) , p ( 1 ) , q ( 1 ) , p ( 2 ) , q ( 2 ) , ⋯   , p ( n ) , q ( n ) ⟩ C=\left \langle q(0), p(1), q(1), p(2), q(2), \cdots, p(n), q(n) \right \rangle C=q(0),p(1),q(1),p(2),q(2),,p(n),q(n),将这些元素存储在一棵二叉树的结点上,以查找 x x x是否在这些数中。如果 x x x不在,确定 x x x在哪个空隙。设法构造一棵最优二叉搜索树使得平均查找次数 t t t最小。一棵二叉搜索树的平均查找次数定义如下:
t = ∑ i = 1 n p ( i ) ( 1 + d ( i ) ) + ∑ j = 0 n q ( j ) d ( j ) t=\sum_{i=1}^{n}{p(i)(1+d(i))}+\sum_{j=0}^{n}{q(j)d(j)} t=i=1np(i)(1+d(i))+j=0nq(j)d(j)
其中, d ( i ) d(i) d(i)表示结点 a i a_i ai的深度, i = 1 , 2 , ⋯   , n i=1,2,\cdots, n i=1,2,,n d ( j ) d(j) d(j)表示空隙(叶子)结点 ( a j , a j + 1 ) (a_j, a_{j+1}) (aj,aj+1)的深度, j = 0 , 1 , ⋯   , n j=0,1,\cdots, n j=0,1,,n

问题建模

1.子问题的边界参数化

S [ i , j ] = < x i , x i + 1 . . . x j > S[i,j]=<x_i,x_{i+1}...x_j> S[i,j]=<xi,xi+1...xj> S S S i i i j j j作为边界的子数据集, C [ i , j ] = < a i − 1 , b i , a i , . . . , b j , a j > C[i,j]=<a_{i-1},b_i,a_i,...,b_j,a_j> C[ij]=<ai1,bi,ai,...,bj,aj>是对应 S [ i , j ] S[i,j] S[i,j]存取概率分布。
子问题划分:以 x k x_k xk作为根划分成两个子问题
S [ i , k − 1 ] , C [ i , k − 1 ] S[i,k-1],C[i,k-1] S[i,k1],C[ik1]
S [ k + 1 , j ] , C [ k + 1 , j ] S[k+1,j],C[k+1,j] S[k+1,j],C[k+1j]

2.递推关系

设m[i,j]是相对于输入S[i,j]和C[i,j]的最优二叉搜索树的平均比较次数,令 w [ i , j ] = ∑ p = i − 1 j a p + ∑ q = i j b q w[i,j]=\sum_{p=i-1}^ja_p+\sum_{q=i}^jb_q w[i,j]=p=i1jap+q=ijbq是C[i,j]中所有概率(包括数据元素与空隙)之和,则递推方程为
{ m [ i , j ] = min ⁡ { m [ i , k − 1 ] + m [ k + 1 , j ] + w [ i , j ] } if  1 ≤ i ≤ j ≤ n m [ i , i − 1 ] = 0 if  i = 1 , 2 , . . . n \begin{cases} m[i,j]=\min \{m[i,k-1]+m[k+1,j]+w[i,j]\} &\text{if } 1\leq i\leq j \leq n \\ m[i,i-1]=0 &\text{if } i=1,2,...n \end{cases} {m[i,j]=min{m[i,k1]+m[k+1,j]+w[i,j]}m[i,i1]=0if 1ijnif i=1,2,...n

3.备忘录表与标记函数表

w:最优二叉搜索树的权;

m:计算最优二叉搜索树的成本;

r:最优二叉搜索树的根。

算法的复杂度分析

i , j i,j i,j的所有组合 O ( n 2 ) O(n^2) O(n2)种,每种要对不同的k进行计算, k = O ( n ) k=O(n) k=O(n)每次计算为常数时间 T ( n ) = O ( n 3 ) , S ( n ) = O ( n 2 ) T(n)=O(n^3),S(n)=O(n^2) T(n)=O(n3),S(n)=O(n2)

算法的迭代实现伪代码描述

 function BST(p, q, n)
 	let m[1...n+1,0...n],w[1...n+1,0...n] and r[1...n,1...n] be new tables
 	for i = 1 → n + 1 do
		m[i, i − 1] ← 0
 		w[i, i − 1] ← qi−1
 	for l = 1 → n do
 		for i = 1 → n − l + 1 do
 			j ← i + l − 1
			m[i, j] ← ∞
 			w[i, j] ← w[i, j − 1] + pj + qj
 			for r = i → j do
 				t ← m[i, r − 1] + m[r + 1, j] + w[i, j]
 				if t < m[i, j] then
 					m[i, j] ← t
 					r[i, j] ← r
 	return m, r
 end function

迭代实现的源代码

#include<iostream>
#include<vector>
using namespace std;
int main(){
	int n;
	cin >> n;
	vector<int> S,C;
	vector<vector<int> > w,m,r;//定义备忘录表 
	vector<int> B;
	for(int i = 1;i <= n;i ++){
		int a;
		cin >> a;
		S.push_back(a);
	}//输入集合S 
	for(int i = 0;i < 2*n+1;i ++){
		double a;
		cin >> a;
		C.push_back(100*a);
    }//输入存取概率,乘以100 
	for(int j = 0;j <= n+1;j++){
		B.push_back(0);
	}
	for(int i = 0;i <= n+1;i++){	
		m.push_back(B);
		w.push_back(B);
		r.push_back(B);
	}
	for(int i = 1;i <= n+1;i ++){
		m[i][i-1] = 0;
		w[i][i-1] = C[2*(i-1)];
	}//初始化备忘录表
	for(int l = 1;l <= n;l ++){
		for(int i = 1;i <= n-l+1;i ++){
			int j = i+l-1;
			m[i][j] = 2147483647;
			w[i][j] = w[i][j-1] + C[2*j-1] + C[2*j];
			for(int root = i;root <= j;root ++){
				int t = m[i][root-1] + m[root+1][j] + w[i][j];
				if(t < m[i][j]){
					m[i][j] = t;
					r[i][j] = root;
				}
			}
		}
	}//利用备忘录法迭代实现构造最优二叉搜索树 
	for(int i = 1;i <= n;i ++){
		for(int j = 1;j <= n;j ++){
			cout << r[i][j] << " ";
		}
		cout << endl;
	}//输出记录根节点的表 
	cout << "最小代价为" << (double)m[1][n]/100; 
	return 0;//输出最小期望代价 
}

运行结果截图

在这里插入图片描述

结束语

没有明确表达的爱意都是错觉

作者:花城

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值