算法作业4 最优二分检索树的实现。
问题描述:给定n个标识符,a1<a2<……<an,已知成功检索的概率p[i],不成功检索的概率q[i],(0<=i<=n),构造一颗检索成本最小的二分检索树。
算法思想:采用动态规划的方法,如果ak为最优二分检索树的跟,则其左子树也是一棵最优二分检索树,同理,右子树也是一棵最优二分检索树。
记由ai+1,ai+2,…,aj和Ei,Ei+1,…,Ej构成的最优二分检索树的预期成本为C(i, j),设二分检索树T以ak为根。则有
COST(L) = C(0,k-1)
COST(R) = C(k,n)
这里做右子树的计算COST都是以其子树的根为第一级来计算的,所以会有成本差额w(0,k)和w(k,n)
c(0,n)=min{c(0,k)+c(k+1,n)+w(0,n)}
w(0,n)=p[k]+w(0,k-1)+w(k,n).
采用向前递推过程:
首先计算所有j-i=1的c(i,j);
然后依次计算j-i=2,3,……n的c(i,j);
c(0,n)等于最优二分检索树的成本。
初始值c(i,i)=0,w(i,i)=q(i),0<=i<=n,
在计算C(i, j)的过程中,记下使之取得最小值的k值,即树Tij的根,记为R(i, j)。
根据R(i,j)推导树的形态。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
float *p,*q;
//float p[5]={-1,3,3,1,1};
//float q[5]={2,3,1,1,1};
float **c,**w;
int **R;
int n;
//int n=4;
char *a[10];
//char a[4][10]={{'d','o'},{'i','f'},{'r','e','a','d'},{'w','h','i','l','e'}};
typedef struct BiTNode{
int num;
BiTNode* Lc;
BiTNode* Rc;
}BiTNode, *BiTree;
//录入标识符集和成功检索概率以及不成功检索概率
void input()
{
int i;
printf("请输入字符个数:");
scanf("%d",&n);
p=(float *)malloc(sizeof(float)*(n+1));
q=(float *)malloc(sizeof(float)*(n+1));
printf("请键入字符集:\n");
for(i=0;i<n;i++)
{
printf("a[%d]=",i);
a[i]=(char *)malloc(sizeof(char)*10);
scanf("%s",a[i]);
}
p[0]=-1;
for(i=1;i<=n;i++)//输入各字符检索成功的概率
{
printf("p[%d]=",i);
scanf("%f",&p[i]);
}
for(i=0;i<=n;i++) //输入检索不成功的概率
{
printf("q[%d]=",i);
scanf("%f",&q[i]);
}
}
void OBST( )
{
c=(float **)malloc(sizeof(float)*(n+1));
w=(float **)malloc(sizeof(float)*(n+1));
R=(int **)malloc(sizeof(int)*(n+1));
int i,j,m,k,l;
float tmp,tmp1;
for(i=0;i<=n;i++)
{
c[i]=(float *)malloc(sizeof(float)*(n+1));
memset(c[i],0,sizeof(float)*(n+1));
w[i]=(float *)malloc(sizeof(float)*(n+1));
memset(w[i],0,sizeof(float)*(n+1));
R[i]=(int *)malloc(sizeof(int)*(n+1));
memset(R[i],0,sizeof(int)*(n+1));
}
for(i=0;i<n;i++)
{
w[i][i]=q[i];
c[i][i]=0;
R[i][i]=0;
w[i][i+1]=q[i+1]+p[i+1]+q[i];
R[i][i+1]=i+1;
c[i][i+1]=q[i+1]+p[i+1]+q[i];
}
w[n][n]=q[n];
R[n][n]=0;
c[n][n]=0;
for(m=1;m<=n;m++)
{//找有m个结点的最优树
for(i=0;i<=n-m;i++)
{
j=i+m;
w[i][j]=w[i][j-1]+q[j]+p[j];
tmp=c[i][i]+c[i+1][j];
k=i+1;
//printf("%d %d\n",R[i][j-1],R[i+1][j]);
for(l=i+2;l<=j;l++)
{
tmp1=c[i][l-1]+c[l][j];
if(tmp1<tmp)
{
tmp=tmp1;
k=l;
}
}
c[i][j]=w[i][j]+c[i][k-1]+c[k][j];
R[i][j]=k;
//printf("c[%d][%d]=%.0f R[%d][%d]=%d\t",i,j,c[i][j],i,j,R[i][j]);
}
// printf("\n");
}
}
BiTree buildtree(int i,int j)
{
if(i>=j)
return NULL;
BiTree Tr;
Tr=(BiTree)malloc(sizeof(BiTNode));
//memset(Tr,0,sizeof(BiTNode));
if(!Tr)
return NULL;
Tr->num=R[i][j];
Tr->Lc=buildtree(i,R[i][j]-1);
Tr->Rc=buildtree(R[i][j],j);
return Tr;
}
void preTree(BiTree T)//先序并输出
{
if(T)
{
printf("%s ",a[T->num-1]);
//printf(" %d ",T->num);
preTree(T->Lc);
preTree(T->Rc);
}
}
void midTree(BiTree T)//中序并输出
{
if(T!=NULL)
{
midTree(T->Lc);
printf("%s ",a[T->num-1]);
midTree(T->Rc);
}
}
int main(int argc, char *argv[])
{
BiTree BT;
input();
OBST();
printf("c[0][%d]=%.2f,R[0][%d]=%d\n",n,c[0][n],n,R[0][n]);
BT=buildtree(0,n);
printf("先序:");
preTree(BT);
printf("\n");
printf("中序:");
midTree(BT);
printf("\n");
system("PAUSE");
return 0;
}