动态规划--最优二叉树问题

 
1、问题描速:
  

     设 S={x1, x2, ···, xn}  是一个有序集合,且x1, x2, ···, xn表示有序集合的二叉搜索树利用二叉树的顶点存储有序集中的元素,而且具有性质:存储于每个顶点中的元素x 大于其左子树中任一个顶点中存储的元素,小于其右子树中任意顶点中存储的元素。二叉树中的叶顶点是形如(xi, xi+1) 的开区间。在表示S的二叉搜索树中搜索一个元素x,返回的结果有两种情形:

    (1) 在二叉树的内部顶点处找到: x = xi
    (2) 在二叉树的叶顶点中确定: x∈ (xi , xi+1)

    设在情形(1)中找到元素x = xi的概率为pi;在情形(2)中确定x∈ (xi , xi+1)的概率为qi。其中约定x0=  -∞ , xn+1= + ∞ ,有

    《动态规划--最优二叉树问题》

    集合{q0,p1,q1,……pn,qn}称为集合S的存取概率分布。    

   最优二叉搜索树在一个表示S的二叉树T中,设存储元素xi的结点深度为ci;叶结点(xj,xj+1)的结点深度为dj

     《动态规划--最优二叉树问题》

    注:在检索过程中,每进行一次比较,就进入下面一层,对于成功的检索,比较的次数就是所在的层数加1。对于不成功的检索,被检索的关键码属于那个外部结点代表的可能关键码集合,比较次数就等于此外部结点的层数。对于图的内结点而言,第0层需要比较操作次数为1,第1层需要比较2次,第2层需要3次。

     w表示在二叉搜索树T中作一次搜索所需的平均比较次数。w又称为二叉搜索树T的平均路长,在一般情况下,不同的二叉搜索树的平均路长是不同的。对于有序集S及其存取概率分布{q0,p1,q1,……pn,qn},在所有表示有序集S的二叉搜索树中找出一棵具有最小平均路长的二叉搜索树。    

      对于有n个关键码的集合,其关键码有n!种不同的排列,可构成的不同二叉搜索树有《动态规划--最优二叉树问题》棵。(n个结点的不同二叉树,卡塔兰数)。如何评价这些二叉搜索树,可以用树的搜索效率来衡量。例如:标识符集{1, 2, 3}={do, if, stop}可能的二分检索树为:

《动态规划--最优二叉树问题》

     若P1=0.5, P2=0.1, P3=0.05,q0=0.15, q1=0.1, q2=0.05, q3=0.05,求每棵树的平均比较次数(成本)。     

     Pa(n)=1 × p1 + 2 × p2+3 × p3 + 1×q0 +2×q1+ 3×( q2 + q3 ) =1 × 0.5+ 2 × 0.1+3 ×0.05 + 1×0.05 +2×0.1+ 3×( 0.05 + 0.05 ) =1.5

     Pb(n)=1 × p1 + 2 × p3+3 × p2 + 1×q0 +2×q3 + 3×( q1 + q2 ) =1 × 0.5+ 2 × 0.05 + 3 ×0.1 + 1×0.15 +2×0.05+ 3×( 0.1 + 0.05 ) =1.6

     Pc(n)=1 × p2 + 2 × (p1 +  p3) + 2×(q0 +q1 +q2 + q3 ) =1 × 0.1+ 2 × (0.5 + 0.05) + 2×(0.15 + 0.1 + 0.05 + 0.05) =1.9

     Pd(n)=1 × p3 + 2 × p1+3 × p2 + 1 × q3+2 × q0 +3 × (q1+ q2) =1 × 0.05 + 2 × 0.5 + 3 × 0.1 + 1×0.05 + 2 × 0.15 + 3 × (0.1 + 0.05) =2.15

     Pe(n)=1 × p3 + 2 × p2+3 × p1 + 1 × q3+2 × q2 +3 × (q0 + q1) =1 × 0.05 + 2 × 0.1+ 3 × 0.5 + 1×0.05 + 2 × 0.15 + 3 × (0.15 + 0.1) =2.85

     因此,上例中的最小平均路长为Pa(n)=1.5。

     可以得出结论:结点在二叉搜索树中的层次越深,需要比较的次数就越多,因此要构造一棵最小二叉树,一般尽量把搜索概率较高的结点放在较高的层次.

 

2.动态规划求解过程

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

  如果一棵最优二叉查找树T有一棵包含关键字ki,……,kj的子树T’,那么这棵子树T’对于对于关键字ki,……kj和虚拟键di-1,……,dj的子问题也必定是最优的。

2)一个递归解

  定义e[i,j]为搜索一棵包含关键字ki,……,kj的最优二叉查找树的期望代价,则分类讨论如下:

当j=i-1时,说明此时只有虚拟键di-1,故e[i,i-1] = qi-1

当j≥i时,需要从ki,……,kj中选择一个跟kr,然后用关键字ki,……,kr-1来构造一棵最优二叉查找树作为左子树,用关键字kr+1,……,kj来构造一棵最优二叉查找树作为右子树。定义一棵有关键字ki,……,kj的子树,定义概率的总和为:

《动态规划--最优二叉树问题》

因此如果kr是一棵包含关键字ki,……,kj的最优子树的根,则有:

《动态规划--最优二叉树问题》

《动态规划--最优二叉树问题》

 

故e[i,j]重写为:

《动态规划--最优二叉树问题》

最终的递归式如下:

《动态规划--最优二叉树问题》

3)计算一棵最优二叉查找树的期望搜索代价

  将e[i,j]的值保存到一个二维数组e[1..1+n,0..n]中,用root[i,j]来记录关键字ki,……,kj的子树的根,采用二维数组root[1..n,1..n]来表示。为了提高效率,防止重复计算,需要个二维数组w[1..n+1,0…n]来保存w(i,j)的值,其中w[i,j] = w[i,j-1]+pj+qj。数组给出了计算过程的伪代码:

《动态规划--最优二叉树问题》

 1 OPTIMAL_BST(p,q,n)
 2     for i=1 to n+1    //初始化e和w的值
 3        do e[i,i-1] = qi-1;
 4           w[i,i-1] = qi-1;
 5      for l=1 to n
 6         do for i=1 to n-l+1
 7                   do j=i+l-1;
 8                        e[i,j] = MAX;
 9                        w[i,j] = w[i,j-1]+pj+qj;
10                        for r=i to j
11                                do t=e[i,r-1]+e[r+1,j]+w[i,j]
12                                     if t<e[i,j]
13                                          then e[i,j] = t;
14                                               root[i,j] = r;
15 return e and root;

《动态规划--最优二叉树问题》

4)构造一棵最优二叉查找树

  根据地第三步中得到的root表,可以递推出各个子树的根,从而可以构建出一棵最优二叉查找树。从root[1,n]开始向下递推,一次找出树根,及左子树和右子树。

3.编程实现

  针对一个具体的实例编程实现,现在有5个关键字,其出现的概率P={0.15,0.10,0.05,0.10,0.20},查找虚拟键的概率q={0.05,0.10,0.05,0.05,0.05,0.10}。采用C++语言是实现如下:

head.h

#include <iostream>
using namespace  std;

#define  N 5
#define MaxValue 1000000
void opimal_bst(float *p, float *q,float e[N+2][N+1],float w[N+2][N+1],int root[N+1][N+1]);
void construct_optimal_bst(int root[N+1][N+1],int i,int j);
void construct_optimal_bst_detail(int root[N+1][N+1],int i,int j);

main.cpp
#include "head.h"
void main()
{
	float p[N+1]={0,0.15,0.1,0.05,0.1,0.2};
	float q[N+1]={0.05,0.1,0.05,0.05,0.05,0.1};
	float e[N+2][N+1];
	float w[N+2][N+1];
	int root[N+1][N+1];
	opimal_bst(p, q,e,w,root);
	cout<<"e:"<<endl;
	int i,j;
	for(i=1;i<=N+1;i++) 
	{
		for (j=i-1;j<=N;j++)
		{
			cout<<e[i][j]<<" ";
		}
		cout<<endl;
	}
	cout<<"the cost of best binary tree  is"<<e[1][N]<<endl;
	cout<<"w:"<<endl;
	for(int i=1;i<=N+1;i++) 
	{
		for (int j=i-1;j<=N;j++)
		{
			cout<<w[i][j]<<" ";
		}
		cout<<endl;
	}
	cout<<"root:"<<endl;
	for(i=1;i<=N;i++)   
	{
		for(j=i;j<=N;j++) 
		{
		cout<<root[i][j]<<" ";
		}
		cout<<endl;
	}
	construct_optimal_bst(root,1,N);
	construct_optimal_bst_detail(root,1,N);
	cout<<endl;
}
void opimal_bst(float *p, float *q,float e[N+2][N+1],float w[N+2][N+1],int root[N+1][N+1])
{
	int i,j,l,r;
	float t;
	for ( i=1;i<=N+1;i++ )
	{
		e[i][i-1]=q[i-1];
		w[i][i-1]=q[i-1];
	}
	for ( l=1;l<=N;l++)
	{
		for (i=1;i<=N-l+1;i++)
		{
			j=i+l-1;
			e[i][j]=MaxValue;
			w[i][j]=w[i][j-1]+p[j]+q[j];
			for ( r=i;r<=j;r++)
			{
				 t=e[i][r-1]+e[r+1][j]+w[i][j];
				if (t<e[i][j])
				{
					e[i][j]=t;
					root[i][j]=r;
				}
			}
		}
	}
}
void construct_optimal_bst(int root[N+1][N+1],int i,int j)
{
	if (i<=j)
	{
		cout<<root[i][j]<<" ";
		construct_optimal_bst(root,i,root[i][j]-1);
		construct_optimal_bst(root,root[i][j]+1,j);
	}
}
void construct_optimal_bst_detail(int root[N+1][N+1],int i,int j)
{
	if (i==1&&j==N)
	{
		cout<<"k"<<root[1][N]<<"is root"<<endl;
	}
	if (i<j)
	{
		int r=root[i][j];
		if (r!=i)
		{
			cout<<"k"<<root[i][r-1]<<"is left child of "<<"k"<<r<<endl;
		}
		construct_optimal_bst_detail(root,i,r-1);
		if (r!=j)
		{
			cout<<"k"<<root[r+1][j]<<"is right child of "<<"k"<<r<<endl;
		}
		construct_optimal_bst_detail(root,r+1,j);
	}
	if (i==j)
	{
		cout<<"d"<<i-1<<"is left child of "<<"k"<<i<<endl;
		cout<<"d"<<i<<"is right child of "<<"k"<<i<<endl;
	}
	if (i>j)
	{
		cout<<"d"<<j<<"is right child of "<<"k"<<j<<endl;
	}
}

 

运行结果为

《动态规划--最优二叉树问题》
算法OptimalBinarySearchTree中用s[i][j]保存最优子树T(i,j)的根节点中的元素。当s[i][n]=k时,xk为所求二叉搜索树根节点元素。其左子树为T(1,k-1)。因此,i=s[1][k-1]表示T(1,k-1)的根节点元素为xi。依次类推,容易由s记录的信息在O(n)时间内构造出所求的最优二叉搜索树。

4.复杂度分析与优化:

   算法中用到3个数组e,w和root,故所需空间复杂度为O(n^2)。算法的主要计算量在于计算《动态规划--最优二叉树问题》。对于固定的r,它需要的计算时间O(j-i+1)=O(r+1)。因此算法所耗费的总时间为:《动态规划--最优二叉树问题》

参考:

http://www.cnblogs.com/Anker/archive/2013/03/13/2958488.html

http://blog.csdn.net/liufeng_king/article/details/8694652

 

 

 

    原文作者:动态规划
    原文地址: https://blog.csdn.net/sinat_24520925/article/details/42880069
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞