3.5最优二叉树

1.最优二叉树定义

扩展二叉树:在对二叉搜索树进行搜索的时候,会遇到检索不成功的情况。当二叉搜索树出现空的子叶时,我们把它补全(以区间的形式),因此扩展二叉树是满二叉树。



最优二叉树:


即bi表示找到结点的概率,

  • a0表示找到区间(负无穷,x1)的概率
  • ai表示找到区间(xi,xi+1)的概率
  • an表示找到区间(xn,正无穷)的概率


对于二叉树中不能搜索到的结点(区间)我们称它伪结点,若树的根节点深度是0,那么对于每个深度为ci的结点,查找次数就是(ci+1),此结点对应的伪结点的深度是dj=ci+1,然而此伪结点查找次数是和其对应父亲节点一样的,即ci+1,即dj

2.最优子结构的证明

即证明对于最优二叉树其左右子树也是最优的。

证明1(文字证明):

若k为s树根,则结点1,2……k-1,伪结点0,1,……k-1位于左子树,结点k+1,k+2……n和伪结点k,k+1……n位于右子树上。若在左子树或右子树中能找到另一个更优的二叉树,那么对于整个树来说,情况就不是最优的了(反证法,切割粘贴法)。

证明2(数学证明):

mij=wij*pij表示对Tij进行一次访问的平均代价

wij表示Tij所有节点概率之和

sij表示子树Tij的根节点

其中wm,m*1是因为以m为根节点,m在子树Ti,j中的深度是1

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;
int a[100],b[100],w[100][100],m[100][100],s[100][100];

void print(int i,int j){
     if(i<j){
        int root=s[i][j];
        printf("S%d是根\n",root);
        if(s[i][root-1]>0) {
            printf("S%d的左孩子是S%d\n",root,s[i][root-1]);
        }
        if(s[root+1][j]>0) {
            printf("S%d的右孩子是S%d\n",root,s[root+1][j]);
        }
        print(i,root-1);
        print(root+1,j);
    }
}

int main(){
    int n;
    printf("请输入结点数目:\n");
    scanf("%d",&n);
    printf("请输入各结点查找成功的概率和失败的概率:\n");
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=0;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=0;i<=n;i++){w[i+1][i]=a[i];m[i+1][i]=0;}
    //w[i+1][i]的值为其对应伪节点的值,对于m数组,mi,j若i>j则说明没有节点只有伪节点,访问代价为0
     for(int r=0;r<n;r++) {//长度
        for (int i=1;i<=n-r;i++){
            int j=i+r;
            w[i][j]=w[i][j-1]+a[j]+b[j];//{ai-1,bi,…aj,bj}={ai-1,bi,…bi-1,aj-1}+aj+bj;
            m[i][j]=m[i+1][j];//i为根节点,i又是树Ti,j的左边界,所以mi,j赋右子树代价mi+1,j
            s[i][j]=i;
            //以上三行是以i为根节点的情况
            for (int k=i+1;k<=j;k++) {
                int t=m[i][k-1]+m[k+1][j];//左子树代价加右子树代价
                if(t<m[i][j]){m[i][j]=t;s[i][j]=k;}
            }
            m[i][j]+=w[i][j];
        }
    }
    print(1,n);
}
/*
5
15 10 5 10 20
5 10 5 5 5 10
*/


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值