C++打印完全二叉树

思路:完全二叉树可以采用数组顺序存储,而且除最后一层外其余各层都是满的。则可以采用逆序打印的方式,先确定最底层的节点位置及数目,进而确定其上各层的节点位置。 

打印效果

代码实现

#include<iostream>
#include<stdlib.h>
#include<string>
#include<vector>
#include<cmath>
#include<time.h>
#include<exception>


using namespace std;

//存储数值节点及树枝的初始位置以及判断是否为空节点
typedef struct{
    int iniloc;
    bool place_hold = false;
}treeNode;          

//存储要打印的每一行字符、起始位置,以及其中存储节点和树枝的栈
class prtTreeLine{
    public:
        string str;
        int iniLoc;
        vector<treeNode>tr;
        vector<treeNode>limb;
};


//处理最底层
void process_Bottom(vector<prtTreeLine> &Bitree,int arr[],int len){
    int tree_height = floor(log2(len)+1);
    int first_node = (int)(pow(2,tree_height-1));
    int maxBasenode = (int)(pow(2,tree_height-1));                  //最底层最大元素个数(满的情况下)
    int base_node_sum = len-first_node+1>0?len-first_node+1:1;      //最底层元素个数(实际节点数)
    prtTreeLine pt;
    string str;
    int ini_loc=0;
    pt.iniLoc = ini_loc;
    for(int j=0;j<=maxBasenode;j++) //遍历最底层的节点
    {
        treeNode tn;
        tn.iniloc = ini_loc;
        string val_str;
        if(j<base_node_sum)       
            {
                val_str = to_string(arr[j+first_node]) + "    ";
                
            }
        else{
            val_str = string(6,' ');     //最底层不是满的,后续节点用6个空格作占位符
            tn.place_hold = true;
        }
        str +=  val_str ;
        ini_loc += val_str.size();
        pt.tr.push_back(tn);
    }
    pt.str = str;
    Bitree.push_back(pt);
}

//处理树枝层
void processLimb(vector<prtTreeLine> &Bitree){
    prtTreeLine pt;
    prtTreeLine last_pt = Bitree.back();
    string str(last_pt.str.size(),' ');     //初始化一个字符串
    int iniloc = 0;
    pt.iniLoc =last_pt.iniLoc+1;
    iniloc = pt.iniLoc;
    for(int g=0;g<last_pt.tr.size();g++)
    {
        treeNode limb;
        if(last_pt.tr[g].place_hold==false)
        {
            if(g%2==0)  //对应左节点
            {
            iniloc =last_pt.tr[g].iniloc+1;     //左孩子头上的枝干位置应为其位置+1
            str.replace(iniloc,1,"/");
            
            }
            else{
                iniloc =last_pt.tr[g].iniloc-1;
                str.replace(iniloc,1,"\\");
            }
        }
        else{
            iniloc =last_pt.tr[g].iniloc+2;
            limb.place_hold = true;
        }
        
        limb.iniloc = iniloc;
        pt.limb.push_back(limb);
    }
    pt.str = str;
    Bitree.push_back(pt);
}


//处理其它节点层
void process_others(vector<prtTreeLine> &Bitree,int arr[],int nodeLayer){
    prtTreeLine pt;
    prtTreeLine last_pt = Bitree.back();
    string str(last_pt.str.size(),' ');     //初始化一个字符串
    int iniloc = 0;
    pt.iniLoc =last_pt.iniLoc+1;
    iniloc = pt.iniLoc;
    int node =0;
    int iniNode = (int)(pow(2,nodeLayer-1));
    int node_sum = (int)(pow(2,nodeLayer))-(int)(pow(2,nodeLayer-1));     //完全二叉树除了最低层应该都是满的

    for(int q=0;q<last_pt.limb.size()&&node<node_sum;q+=2,node++)
    {
        treeNode tn;
        int mid;
        if(q+1<last_pt.limb.size())
        {
            mid =last_pt.limb[q].iniloc+ (last_pt.limb[q+1].iniloc-last_pt.limb[q].iniloc)/2;       //节点所在位置应为其左右枝干中间
            string val_str = to_string(arr[node+iniNode]);
            str.replace(mid,val_str.size(),val_str);
            if(last_pt.limb[q].place_hold==false)       //如果该节点有孩子节点
                {
                    int frspace = mid-last_pt.limb[q].iniloc-1;
                    frspace = frspace>0?frspace:0;
                    int baspace = last_pt.limb[q+1].iniloc-mid-val_str.size();
                    baspace = baspace>0?baspace:0;
                    string front_str(frspace,'_');      //用下划线充填节点与左孩子树枝之间的空格
                    string back_str(baspace,'_');
                    if(frspace)
                        str.replace(last_pt.limb[q].iniloc+1,frspace,front_str);
                    if(last_pt.limb[q+1].place_hold ==false) //如果该节点有右孩子
                    {
                        if(baspace)
                        str.replace(mid+val_str.size(),baspace,back_str);
                    }
                }
            iniloc =mid;
            tn.iniloc = iniloc;
            pt.tr.push_back(tn);
            
        }
    }
    pt.str = str;
    Bitree.push_back(pt);
    
}


//打印一颗完全二叉树
void treePrint(int arr[],int len)
{
    void process_Bottom(vector<prtTreeLine> &Bitree,int arr[],int len);
    void processLimb(vector<prtTreeLine> &Bitree);
    void process_others(vector<prtTreeLine> &Bitree,int arr[],int nodeLayer);



    vector<prtTreeLine>Bitree;
    int tree_height = floor(log2(len)+1);
    int layer = tree_height*2-2;

    process_Bottom(Bitree,arr,len);

    for(int nodeLayer=tree_height-1;layer>0;--layer)      //从最底层开始逆序打印
    {
        prtTreeLine last_pt = Bitree.back();
        if(last_pt.limb.size()!=0)
        {
            //上一行为树枝行,本行应打印节点行
            //其它层
            process_others(Bitree,arr,nodeLayer);
            nodeLayer--;        //nodeLayer为当前节点层号
        }
        else{
            //上一行为节点行,本行应打印树干行
            processLimb(Bitree);
        }

    }

    cout<<"***********打印一颗完全二叉树**************"<<endl;
    while(!Bitree.empty())
    {
        cout<<Bitree.back().str<<endl;
        Bitree.pop_back();
    }
    
}


//生成一个随机数组
void getRandarray(int arr[],int len)
{
    srand(time(NULL));
    cout<<"原始序列:";
    for(int i=1;i<=len; i++)     //完全二叉树从序号1开始排序
    {
        arr[i] = rand()%100+1;
        cout<<arr[i]<<" ";
    }
    cout<<endl;

}
   

int main()
{
    int len = 27;
    int *arr = new int[len+1];      //完全二叉树从序号1开始排序
    getRandarray(arr,len);
    try{
        treePrint(arr,len);
    }catch(exception &e){
    
        cerr<<e.what()<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daimashiren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值