Complete Binary Search Tree

基本思路,完全二叉树有这么一个性质,如果二叉树的root从下标为0的位置开始,若a节点的下标为i,那么它左儿子的下标为2i+1。右儿子为2i+2。(下标从1开始的话,左儿子的下标为2i,右儿子为2i+1)。
这个下标则为完全二叉树在层序遍历时的输出顺序。而对于任意一棵搜索树,其中序遍历的输出,是一个递增的数列。根据这两个性质,可以有如下算法。

首先,将输入的数列递增排序,会用到sort函数将输入的数据排序。这样,得到了所求的完全二叉搜索树的中序遍历输出,得到数组a[i]。接着,根据总的节点个数,将这个完全二叉搜索树的层序遍历的顺序(或者下标),中序遍历输出,得到数组b[i]。

即有一棵完全的二叉搜索树,每个节点上除了 data,left以及right以外,还有一个flag,用来记录他是第几个元素(按照层序遍历的顺序)。现在有它的中序遍历的输出,那么,只要在这个中序遍历的输出里面,按照每个节点对应的层序遍历的flag,输出,就是层序遍历的输出值了。

对于如何中序的输出层序遍历的顺序,可以参考如何中序的输出节点。类比得:终止条件,输入的 i 大于总的元素数N。递归的顺序,root的顺序是i,则先让2i+1入递归,然后输出i,接着让2i+2入递归。

#include "stdio.h"
int b[10]={};

void Sort(int a[])
{
    for(int i=0;i<10;i++)
        for(int j = 0; j<10-i-1;j++)
            if(a[j]>a[j+1]){
                int tmp = a[j];
                a[j] = a[j+1];
                a[j+1] = tmp;
            }
}

void mid_tre(int root, int N,int a[])
{
    if(root<=N){
        static int i = 0;
        mid_tre(root*2+1,N,a);
        /*因为数组a从0开始,所以左子树root*2+1,如果数组a从1开始,则左子树root*2*/
        b[root] = a[i++];
        mid_tre(root*2+2,N,a);
    }
}

int main()
{
    int a[10];
    for(int i =0; i<10; i++)
        scanf("%d",&a[i]);
    printf("\n");
    Sort(a);
    for(int i =0; i<10; i++)
        printf("%d  ",a[i]);
    printf("\n");
    mid_tre(0,9,a);
    for(int i =0; i<10; i++)
        printf("%d  ",b[i]);
    return 0;
}

我们还可以通过每次类似先序遍历的方法来解决问题

#include "stdio.h"

int a[10];
int b[10]={};

void Sort(int a[])
{
    for(int i=0;i<10;i++)
        for(int j = 0; j<10-i-1;j++)
            if(a[j]>a[j+1]){
                int tmp = a[j];
                a[j] = a[j+1];
                a[j+1] = tmp;
            }
}

int GetLeftLength(int n)
{
    int H=0,t = 1,X=1,Last;
    int N=n+1;
    while(N>1){
        N/=2;
        H++;
    } //计算完全二叉树部分的H值
    printf("H = %d\n",H);
    for(int i=0;i<H;i++)
        t*=2;
    Last=n-t+1; //最后一层的节点数
    for(int i=0;i<H-1;i++)
        X*=2;  //左子树是满树的情况下,左子树最后一层的结点数
    if(Last <= X)  //判断左子树是否满
        return Last+(t-1)/2;
    else
        return X+(t-1)/2;
}

void solve(int ALeft,int ARight,int TRoot)
/*ALeft 当前树的最左端的下标,从0开始,ARight 当前树的最后端,从n-1开始*/
{
    int n=ARight-ALeft+1;
    if(n==0) return;
    int Lnum = GetLeftLength(n); //计算n个结点的树中,左子树的结点的个数
    b[TRoot] = a[ALeft+Lnum];
    int LeftRoot = TRoot*2+1; //数组从0开始存储,则左孩子为2*n+1;
    int RightRoot = LeftRoot +1;
    solve(ALeft,ALeft+Lnum-1,LeftRoot); //遍历左子数
    solve(ALeft+Lnum+1,ARight,RightRoot);
}

int main()
{

    for(int i =0; i<10; i++)
        scanf("%d",&a[i]);
    Sort(a);
    solve(0,9,0);
    for(int i =0; i<10; i++)
        printf("%d ",a[i]);
    printf("\n");
    for(int i =0; i<10; i++)
        printf("%d ",b[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值