最优二叉搜索树java_动态规划方法生成最优二叉查找树

本文介绍了如何利用动态规划方法构建最优二叉搜索树。通过统计元素的查找概率,目标是使查找过程中键值比较次数最少,从而达到平均查找次数最小。文章详细阐述了问题的提出、分段解决策略、递推计算式,并给出了具体的Java实现代码,最后展示了运行结果。
摘要由CSDN通过智能技术生成

1、概念引入

基于统计先验知识,我们可统计出一个数表(集合)中各元素的查找概率,理解为集合各元素的出现频率。比如中文输入法字库中各词条(单字、词组等)的先验概率,针对用户习惯可以自动调整词频——所谓动态调频、高频先现原则,以减少用户翻查次数。这就是最优二叉查找树问题:查找过程中键值比较次数最少,或者说希望用最少的键值比较次数找到每个关键码(键值)。为解决这样的问题,显然需要对集合的每个元素赋予一个特殊属性——查找概率。这样我们就需要构造一颗最优二叉查找树。

2、问题给出

n个键{a1,a2,a3......an},其相应的查找概率为{p1,p2,p3......pn}。构成最优BST,表示为T

1

n ,求这棵树的平均查找次数C[1, n](耗费最低)。换言之,如何构造这棵最优BST,使得C[1, n] 最小。

3、分段方法

动态规划法策略是将问题分成多个阶段,逐段推进计算,后继实例解由其直接前趋实例解计算得到。对于最优BST问题,利用减一技术和最优性原则,如果前n-1个节点构成最优BST,加入一个节点

an 后要求构成规模n的最优BST。按 n-1, n-2 , ... , 2, 1 递归,问题可解。自底向上计算:C[1, 2]→C[1, 3] →... →C[1, n]。为不失一般性用C[i, j] 表示由{a1,a2,a3......an}构成的BST的耗费。其中1≤i ≤j ≤n。这棵树表示为Tij。从中选择一个键ak作根节点,它的左子树为Tik-1,右子树为Tk+1j。要求选择的k 使得整棵树的平均查找次数C[i, j]最小。左右子树递归执行此过程。(根的生成过程)

4、递推计算式

8f44e59ebd25e94e6fc2ab74ae3ba653.png

5、基本算法如下

af91a781759b287e266803eda9aa1d37.png

6、具体实现代码(其中所有数据都存放在2.txt中,其内容为:

277c0120aa47f9638886ad539ecee94e.png

其中5表示有5个节点,其他数据表示各个节点出现的概率:

#include

#include

#define max 9999

void OptimalBST(int,float*,float**,int**);

void OptimalBSTPrint(int,int,int**);

void main()

{

int i,num;

FILE *point;

//所有数据均从2.txt中获取,2.txt中第一个数据表示节点个数;从第二个数据开始表示各个节点的概率

point=fopen("2.txt","r");

if(point==NULL)

{

printf("cannot open 2.txt.\n");

exit(-1);

}

fscanf(point,"%d",&num);

printf("%d\n",num);

float *p=(float*)malloc(sizeof(float)*(num+1));

for(i=1;i

fscanf(point,"%f",&p[i]);

//创建主表;

float **c=(float**)malloc(sizeof(float*)*(num+2));

for(i=0;i

c[i]=(float*)malloc(sizeof(float)*(num+1));

//创建根表;

int **r=(int**)malloc(sizeof(int*)*(num+2));

for(i=0;i

r[i]=(int*)malloc(sizeof(int)*(num+1));

//动态规划实现最优二叉查找树的期望代价求解。。

OptimalBST(num,p,c,r);

printf("该最优二叉查找树的期望代价为:%f \n",c[1][num]);

//给出最优二叉查找树的中序遍历结果;

printf("构造成的最优二叉查找树的中序遍历结果为:");

OptimalBSTPrint(1,4,r);

}

void OptimalBST(int num,float*p,float**c,int**r)

{

int d,i,j,k,s,kmin;

float temp,sum;

for(i=1;i

{

c[i][i-1]=0;

c[i][i]=p[i];

r[i][i]=i;

}

c[num+1][num]=0;

for(d=1;d<=num-1;d++)//加入节点序列

{

for(i=1;i<=num-d;i++)

{

j=i+d;

temp=max;

for(k=i;k<=j;k++)//找最优根

{

if(c[i][k-1]+c[k+1][j]

{

temp=c[i][k-1]+c[k+1][j];

kmin=k;

}

}

r[i][j]=kmin;//记录最优根

sum=p[i];

for(s=i+1;s<=j;s++)

sum+=p[s];

c[i][j]=temp+sum;

}

}

}

//采用递归方式实现最优根的输出,最优根都是保存在r[i][j]中的。。。

void OptimalBSTPrint(int first,int last,int**r)

{

int k;

if(first<=last)

{

k=r[first][last];

printf("%d ",k);

OptimalBSTPrint(first,k-1,r);

OptimalBSTPrint(k+1,last,r);

}

}

7、最终运行结果:

a561aac7a23ceec22c1c673e27a082ad.png

8、参考文献:

(1)算法导论

(2)数据结构 严蔚敏

(3)网上下载的一个ppt(算法设计与分析,第八章)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值