仲舟の原创算法——树与二叉树的相互转换

本文介绍了一种树与二叉树之间的相互转换方法,并提供了详细的实现步骤与代码示例。通过递归与循环的方式实现了两种数据结构的互相转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是我有史以来做过最难的数据结构,没查找任何资料写的题目,我尽量备注清楚方便大家读懂。

///*题目:树与二叉树的相互转换
///*作者:仲舟
///*难度:★★★★★★
///*完成时间:2021.05.10
#include<stdio.h>
#define M 3//树的度数
#define MAXSIZE 100//最大结点数

typedef struct bnode { /*二叉树结构定义*/
    char data;
    struct bnode *lchild,*rchild;
} binnode;
typedef binnode *bintree;

typedef struct tnode {/*树的结构定义*/
    char data;
    struct tnode *child[M];
} node;
typedef  node *tree;

tree CreateTree();/*按前序遍历顺序建立一棵树,返回树根地址*/
bintree CreateBinTree();/*按前序遍历顺序建立一棵二叉树,返回树根地址*/
bintree FromTreeToBintree(tree t);/*将树转化为二叉树*/
tree FromBintreeToTree(bintree bt);/*将二叉树转化为树*/
void PreOrderTree(tree t);/*打印树*/
void PreOrderBinTree(bintree bt);/*打印二叉树*/

int main() {
    printf("这里是仲舟的树与二叉树转化程序\n");
    tree a;//a是普通树
    bintree b;//b是二叉树
    /*1.树转二叉树*/
    printf("请用前序遍历的方法输入度数为3的树:");
    a=CreateTree();//创建a树
    getchar();//读取回车
    printf("此树前序遍历为:");
    PreOrderTree(a);//输出a前序遍历
    printf("\n");
    b=FromTreeToBintree(a);//将a树转化为二叉树b
    printf("转换成二叉树后为:");
    PreOrderBinTree(b);//输出b树
    printf("\n");
    /*2.二叉树转树*/
    printf("请用前序遍历的方法输入二叉树树:");
    b=CreateBinTree();
    getchar();//读取回车
    printf("此树前序遍历为:");
    PreOrderBinTree(b);
    printf("\n");
    a=FromBintreeToTree(b);
    printf("转换成树后为:");
    PreOrderTree(a);
    printf("\n");
    return 0;
}

tree  CreateTree() {
    int i;
    char ch;
    tree t;
    if ((ch=getchar())=='#')  t=NULL;
    else {
        t=(tree) malloc (sizeof(node));
        t->data=ch;
        for (i=0; i<M; ++i)
            t->child[i]= CreateTree();
    }
    return t;
}

bintree  CreateBinTree() {
    char ch;
    bintree t;
    if ((ch=getchar())=='#')  t=NULL;
    else {
        t=(bintree)malloc(sizeof(binnode));
        t->data=ch;
        t->lchild=CreateBinTree();
        t->rchild=CreateBinTree();
    }
    return t;
}

bintree FromTreeToBintree(tree t) {
    /*仲舟提示:在树转二叉树的时候,由于二叉树左边孩子,右边兄弟,如果要访问兄弟,就不能用递归,
    和中序遍历一样使用循环+队列的形式,因为访问兄弟需要把父亲先存起来*/
    /*1.声明变量*/
    tree tqueue[MAXSIZE],tnow;//队列,正在处理的结点
    bintree bqueue[MAXSIZE],bt,bnow,blast;//同步队列(和前面的队列同步,建立这个是后续需要引用此类型的指针,存储内容和前队列一样),新生二叉树的根,正在处理的结点,上一个处理的结点(类似链表,要连接就要两个结点,所以要保存前后数据)
    int l=0,r=0;//队列最左下标,队列最右下标
    /*2.队列初始化*/
    bt=(bintree)malloc(sizeof(binnode));//开辟空间
    bt->data=t->data;//新建树的根
    bt->lchild=NULL;//左孩子初始化
    bt->rchild=NULL;//右孩子初始化
    tqueue[r]=t;//树根入队
    bqueue[r]=bt;//树根入队
    r++;
    /*3.开始转化*/
    while(l<r) { //队列还有结点
        tnow=tqueue[l];//开始处理最左边的结点
        blast=bqueue[l];//上一个处理的结点
        l++;//左下标右移
        int flag=0;//第一个孩子标记
        for(int i=0; i<M; i++) //开始连接孩子
            if(tnow->child[i]!=NULL) {//如果有孩子
                /*1.开辟空间*/
                bnow=(bintree)malloc(sizeof(binnode));//【新建】开辟空间
                bnow->data=tnow->child[i]->data;//【赋值】拷贝
                bnow->lchild=NULL;//左孩子初始化
                bnow->rchild=NULL;//右孩子初始化
                /*2.分类讨论*/
                if(flag==0) { //对二叉来说,如果他还没有孩子的时候,这个孩子就是now的左孩子
                    blast->lchild=bnow;//【连接1】与上一个结点相连
                    flag=1;//对树来说,第一个孩子已出现
                } else { //对二叉来说,如果他有孩子了,这个孩子就是那个孩子的右孩子
                    blast->rchild=bnow;//【连接2】与上一个结点相连
                }
                /*3.记忆结点*/
                blast=bnow;//处理完了,这个就是上一个结点
                tqueue[r]=tnow->child[i];//它的孩子入队
                bqueue[r]=bnow;//同步入队
                r++;//右下标右移
            }
    }
    return bt;
}

tree FromBintreeToTree(bintree bt) {
    /*仲舟提示:根据上述函数逆向思维,一个二叉树结点的左、右、右、右……孩子就是树的所有孩子*/
    bintree bqueue[MAXSIZE],bnow;//队列,正在处理的结点
    tree tqueue[MAXSIZE],t,tnow,tlast;//同步队列(和前面的队列同步,建立这个是后续需要引用此类型的指针,存储内容和前队列一样),新生树的根,正在处理的结点,上一个处理的结点(类似链表,要连接就要两个结点,所以要保存前后数据)
    int l=0,r=0;//队列最左下标,队列最右下标
    /*2.队列初始化*/
    t=(tree)malloc(sizeof(node));//开辟空间
    t->data=bt->data;//新建树的根
    for(int i=0; i<M; i++)//孩子初始化
        t->child[i]=NULL;
    tqueue[r]=t;//树根入队
    bqueue[r]=bt;//树根入队
    r++;
    /*3.开始转化*/
    while(l<r) { //队列还有结点
        bnow=bqueue[l];//开始处理最左边的结点
        tlast=tqueue[l];//上一个处理的结点(父结点)
        l++;//左下标右移
        for(int i=0; i<M; i++)//父节点最多M个孩子
            if(i==0&&bnow->lchild||i!=0&&bnow->rchild) {//如果树有孩子的条件(即二叉树有左、右、右……孩子)
                /*1.开辟空间*/
                tnow=(tree)malloc(sizeof(node));//【新建】开辟空间
                for(int j=0; j<M; j++)//孩子初始化
                    tnow->child[j]=NULL;
                /*2.分类讨论*/
                if(i==0) {//如果是树的第一个孩子,那么是二叉树的左孩子
                    tnow->data=bnow->lchild->data;//【赋值1】拷贝
                    bnow=bnow->lchild;//处理完了,这个就是上一个结点
                } else {//如果是树的第二、三个孩子,那么是二叉树左孩子的右孩子的右孩子……
                    tnow->data=bnow->rchild->data;//【赋值2】拷贝
                    bnow=bnow->rchild;//处理完了,这个就是上一个结点
                }
                tlast->child[i]=tnow;//【连接】与父结点连接
                /*3.记忆结点*/
                tqueue[r]=tnow;//它的孩子入队
                bqueue[r]=bnow;//同步入队
                r++;//右下标右移
            }
    }
    return t;
}

void PreOrderTree(tree t) {  /* t为指向树根结点的指针,输出树的前序遍历序列*/
    if(t) { //如果不为空
        printf("%c",t->data);//先输出老子
        for(int i=0; i<=M-1; i++) //再找孩子
            if(t->child[i])//如果有孩子
                PreOrderTree(t->child[i]);
    }
    //如果空,则终止递归
}

void PreOrderBinTree(bintree bt) {  /* t为指向树根结点的指针,输出树的前序遍历序列*/
    if(bt) { //如果不为空
        printf("%c",bt->data);//先输出老子
        if(bt->lchild)//如果有孩子
            PreOrderBinTree(bt->lchild);
        if(bt->rchild)//如果有孩子
            PreOrderBinTree(bt->rchild);
    }
    //如果空,则终止递归
}

仲舟原创,未经允许禁止转载!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值